decoder: drops unused 'expected' utility method
[luajson.git] / lua / json / decode / util.lua
blob2493bf3f8afbc2de7d8c746515474d5ee8fb894b
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
5 local lpeg = require("lpeg")
6 local select = select
7 local pairs, ipairs = pairs, ipairs
8 local tonumber = tonumber
9 local string_char = require("string").char
10 local rawset = rawset
11 local jsonutil = require("json.util")
13 local error = error
14 local setmetatable = setmetatable
16 local table_concat = require("table").concat
18 local merge = require("json.util").merge
20 local _ENV = nil
22 local function get_invalid_character_info(input, index)
23 local parsed = input:sub(1, index)
24 local bad_character = input:sub(index, index)
25 local _, line_number = parsed:gsub('\n',{})
26 local last_line = parsed:match("\n([^\n]+.)$") or parsed
27 return line_number, #last_line, bad_character, last_line
28 end
30 local function build_report(msg)
31 local fmt = msg:gsub("%%", "%%%%") .. " @ character: %i %i:%i [%s] line:\n%s"
32 return lpeg.P(function(data, pos)
33 local line, line_index, bad_char, last_line = get_invalid_character_info(data, pos)
34 local text = fmt:format(pos, line, line_index, bad_char, last_line)
35 error(text)
36 end) * 1
37 end
38 local function unexpected()
39 local msg = "unexpected character"
40 return build_report(msg)
41 end
42 local function denied(item, option)
43 local msg
44 if option then
45 msg = ("'%s' denied by option set '%s'"):format(item, option)
46 else
47 msg = ("'%s' denied"):format(item)
48 end
49 return build_report(msg)
50 end
52 -- 09, 0A, 0B, 0C, 0D, 20
53 local ascii_space = lpeg.S("\t\n\v\f\r ")
54 local unicode_space
56 local chr = string_char
57 local u_space = ascii_space
58 -- \u0085 \u00A0
59 u_space = u_space + lpeg.P(chr(0xC2)) * lpeg.S(chr(0x85) .. chr(0xA0))
60 -- \u1680 \u180E
61 u_space = u_space + lpeg.P(chr(0xE1)) * (lpeg.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E))
62 -- \u2000 - \u200A, also 200B
63 local spacing_end = ""
64 for i = 0x80,0x8b do
65 spacing_end = spacing_end .. chr(i)
66 end
67 -- \u2028 \u2029 \u202F
68 spacing_end = spacing_end .. chr(0xA8) .. chr(0xA9) .. chr(0xAF)
69 u_space = u_space + lpeg.P(chr(0xE2, 0x80)) * lpeg.S(spacing_end)
70 -- \u205F
71 u_space = u_space + lpeg.P(chr(0xE2, 0x81, 0x9F))
72 -- \u3000
73 u_space = u_space + lpeg.P(chr(0xE3, 0x80, 0x80))
74 -- BOM \uFEFF
75 u_space = u_space + lpeg.P(chr(0xEF, 0xBB, 0xBF))
76 unicode_space = u_space
77 end
79 local identifier = lpeg.R("AZ","az","__") * lpeg.R("AZ","az", "__", "09") ^0
81 local hex = lpeg.R("09","AF","af")
82 local hexpair = hex * hex
84 local comments = {
85 cpp = lpeg.P("//") * (1 - lpeg.P("\n"))^0 * lpeg.P("\n"),
86 c = lpeg.P("/*") * (1 - lpeg.P("*/"))^0 * lpeg.P("*/")
89 local comment = comments.cpp + comments.c
91 local ascii_ignored = (ascii_space + comment)^0
93 local unicode_ignored = (unicode_space + comment)^0
95 -- Parse the lpeg version skipping patch-values
96 -- LPEG <= 0.7 have no version value... so 0.7 is value
97 local DecimalLpegVersion = lpeg.version and tonumber(lpeg.version():match("^(%d+%.%d+)")) or 0.7
99 local function setObjectKeyForceNumber(t, key, value)
100 key = tonumber(key) or key
101 return rawset(t, key, value)
104 local util = {
105 unexpected = unexpected,
106 denied = denied,
107 ascii_space = ascii_space,
108 unicode_space = unicode_space,
109 identifier = identifier,
110 hex = hex,
111 hexpair = hexpair,
112 comments = comments,
113 comment = comment,
114 ascii_ignored = ascii_ignored,
115 unicode_ignored = unicode_ignored,
116 DecimalLpegVersion = DecimalLpegVersion,
117 get_invalid_character_info = get_invalid_character_info,
118 setObjectKeyForceNumber = setObjectKeyForceNumber
121 return util