Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3de68fa
commit 6426a66
Showing
21 changed files
with
1,654 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
The following license is applied to all documents in this project with the | ||
exception of the 'tests' directory at the root. | ||
The 'tests' directory is dual-licenses Public Domain / MIT, whichever is | ||
least restrictive in your legal jurisdiction. | ||
|
||
The MIT License | ||
|
||
Copyright (c) 2008 Thomas Harning Jr. <harningt@gmail.com> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--[[ | ||
Licensed according to the included 'LICENSE' document | ||
Author: Thomas Harning Jr <harningt@gmail.com> | ||
]] | ||
local decode = require("json.decode") | ||
local encode = require("json.encode") | ||
local util = require("json.util") | ||
|
||
module("json") | ||
_M.decode = decode | ||
_M.encode = encode | ||
_M.util = util |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
--[[ | ||
Licensed according to the included 'LICENSE' document | ||
Author: Thomas Harning Jr <harningt@gmail.com> | ||
]] | ||
local lpeg = require("lpeg") | ||
|
||
local error = error | ||
|
||
local object = require("json.decode.object") | ||
local array = require("json.decode.array") | ||
|
||
local merge = require("json.util").merge | ||
local util = require("json.decode.util") | ||
|
||
local setmetatable, getmetatable = setmetatable, getmetatable | ||
local assert = assert | ||
local ipairs, pairs = ipairs, pairs | ||
local string_char = string.char | ||
|
||
local require = require | ||
module("json.decode") | ||
|
||
local modulesToLoad = { | ||
"array", | ||
"object", | ||
"strings", | ||
"number", | ||
"calls", | ||
"others" | ||
} | ||
local loadedModules = { | ||
} | ||
|
||
default = { | ||
unicodeWhitespace = true, | ||
initialObject = false | ||
} | ||
|
||
local modes_defined = { "default", "strict", "simple" } | ||
|
||
simple = {} | ||
|
||
strict = { | ||
unicodeWhitespace = true, | ||
initialObject = true | ||
} | ||
|
||
-- Register generic value type | ||
util.register_type("VALUE") | ||
for _,name in ipairs(modulesToLoad) do | ||
local mod = require("json.decode." .. name) | ||
for _, mode in pairs(modes_defined) do | ||
if mod[mode] then | ||
_M[mode][name] = mod[mode] | ||
end | ||
end | ||
loadedModules[name] = mod | ||
-- Register types | ||
if mod.register_types then | ||
mod.register_types() | ||
end | ||
end | ||
|
||
-- Shift over default into defaultOptions to permit build optimization | ||
local defaultOptions = default | ||
default = nil | ||
|
||
|
||
local function buildDecoder(mode) | ||
mode = mode and merge({}, defaultOptions, mode) or defaultOptions | ||
local ignored = mode.unicodeWhitespace and util.unicode_ignored or util.ascii_ignored | ||
-- Store 'ignored' in the global options table | ||
mode.ignored = ignored | ||
|
||
local value_id = util.types.VALUE | ||
local value_type = lpeg.V(value_id) | ||
local object_type = lpeg.V(util.types.OBJECT) | ||
local array_type = lpeg.V(util.types.ARRAY) | ||
local grammar = { | ||
[1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type | ||
} | ||
for _, name in pairs(modulesToLoad) do | ||
local mod = loadedModules[name] | ||
mod.load_types(mode[name], mode, grammar) | ||
end | ||
-- HOOK VALUE TYPE WITH WHITESPACE | ||
grammar[value_id] = ignored * grammar[value_id] * ignored | ||
grammar = lpeg.P(grammar) * ignored * lpeg.Cp() * -1 | ||
return function(data) | ||
local ret, next_index = lpeg.match(grammar, data) | ||
assert(nil ~= next_index, "Invalid JSON data") | ||
return ret | ||
end | ||
end | ||
|
||
-- Since 'default' is nil, we cannot take map it | ||
local defaultDecoder = buildDecoder(default) | ||
local prebuilt_decoders = {} | ||
for _, mode in pairs(modes_defined) do | ||
if _M[mode] ~= nil then | ||
prebuilt_decoders[_M[mode]] = buildDecoder(_M[mode]) | ||
end | ||
end | ||
|
||
--[[ | ||
Options: | ||
number => number decode options | ||
string => string decode options | ||
array => array decode options | ||
object => object decode options | ||
initialObject => whether or not to require the initial object to be a table/array | ||
allowUndefined => whether or not to allow undefined values | ||
]] | ||
function getDecoder(mode) | ||
mode = mode == true and strict or mode or default | ||
local decoder = mode == nil and defaultDecoder or prebuilt_decoders[mode] | ||
if decoder then | ||
return decoder | ||
end | ||
return buildDecoder(mode) | ||
end | ||
|
||
function decode(data, mode) | ||
local decoder = getDecoder(mode) | ||
return decoder(data) | ||
end | ||
|
||
local mt = getmetatable(_M) or {} | ||
mt.__call = function(self, ...) | ||
return decode(...) | ||
end | ||
setmetatable(_M, mt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
--[[ | ||
Licensed according to the included 'LICENSE' document | ||
Author: Thomas Harning Jr <harningt@gmail.com> | ||
]] | ||
local lpeg = require("lpeg") | ||
|
||
local util = require("json.decode.util") | ||
local jsonutil = require("json.util") | ||
|
||
local table_maxn = table.maxn | ||
|
||
local unpack = unpack | ||
|
||
module("json.decode.array") | ||
|
||
-- Utility function to help manage slighly sparse arrays | ||
local function processArray(array) | ||
local max_n = table_maxn(array) | ||
-- Only populate 'n' if it is necessary | ||
if #array ~= max_n then | ||
array.n = max_n | ||
end | ||
if jsonutil.InitArray then | ||
array = jsonutil.InitArray(array) or array | ||
end | ||
return array | ||
end | ||
|
||
local defaultOptions = { | ||
trailingComma = true | ||
} | ||
|
||
default = nil -- Let the buildCapture optimization take place | ||
strict = { | ||
trailingComma = false | ||
} | ||
|
||
local function buildCapture(options, global_options) | ||
local ignored = global_options.ignored | ||
-- arrayItem == element | ||
local arrayItem = lpeg.V(util.types.VALUE) | ||
local arrayElements = lpeg.Ct(arrayItem * (ignored * lpeg.P(',') * ignored * arrayItem)^0 + 0) / processArray | ||
|
||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||
local capture = lpeg.P("[") | ||
capture = capture * ignored | ||
* arrayElements * ignored | ||
if options.trailingComma then | ||
capture = capture * (lpeg.P(",") + 0) * ignored | ||
end | ||
capture = capture * lpeg.P("]") | ||
return capture | ||
end | ||
|
||
function register_types() | ||
util.register_type("ARRAY") | ||
end | ||
|
||
function load_types(options, global_options, grammar) | ||
local capture = buildCapture(options, global_options) | ||
local array_id = util.types.ARRAY | ||
grammar[array_id] = capture | ||
util.append_grammar_item(grammar, "VALUE", lpeg.V(array_id)) | ||
end |
Oops, something went wrong.