Ajout des compendiums light

This commit is contained in:
2021-03-17 17:45:57 +01:00
parent 0365cc213f
commit f1da8606f2
29 changed files with 7938 additions and 0 deletions

View File

@ -0,0 +1,110 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local jsonutil = require("json.util")
local type = type
local pairs = pairs
local assert = assert
local table = require("table")
local math = require("math")
local table_concat = table.concat
local math_floor, math_modf = math.floor, math.modf
local jsonutil = require("json.util")
local util_IsArray = jsonutil.IsArray
local _ENV = nil
local defaultOptions = {
isArray = util_IsArray
}
local modeOptions = {}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode])
end
--[[
Utility function to determine whether a table is an array or not.
Criteria for it being an array:
* ExternalIsArray returns true (or false directly reports not-array)
* If the table has an 'n' value that is an integer >= 1 then it
is an array... may result in false positives (should check some values
before it)
* It is a contiguous list of values with zero string-based keys
]]
local function isArray(val, options)
local externalIsArray = options and options.isArray
if externalIsArray then
local ret = externalIsArray(val)
if ret == true or ret == false then
return ret
end
end
-- Use the 'n' element if it's a number
if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then
return true
end
local len = #val
for k,v in pairs(val) do
if type(k) ~= 'number' then
return false
end
local _, decim = math_modf(k)
if not (decim == 0 and 1<=k) then
return false
end
if k > len then -- Use Lua's length as absolute determiner
return false
end
end
return true
end
--[[
Cleanup function to unmark a value as in the encoding process and return
trailing results
]]
local function unmarkAfterEncode(tab, state, ...)
state.already_encoded[tab] = nil
return ...
end
local function getEncoder(options)
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
local function encodeArray(tab, state)
if not isArray(tab, options) then
return false
end
-- Make sure this value hasn't been encoded yet
state.check_unique(tab)
local encode = state.encode
local compositeEncoder = state.outputEncoder.composite
local valueEncoder = [[
for i = 1, (composite.n or #composite) do
local val = composite[i]
PUTINNER(i ~= 1)
val = encode(val, state)
val = val or ''
if val then
PUTVALUE(val)
end
end
]]
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state))
end
return { table = encodeArray }
end
local array = {
mergeOptions = mergeOptions,
isArray = isArray,
getEncoder = getEncoder
}
return array

View File

@ -0,0 +1,68 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local table = require("table")
local table_concat = table.concat
local select = select
local getmetatable, setmetatable = getmetatable, setmetatable
local assert = assert
local jsonutil = require("json.util")
local isCall, decodeCall = jsonutil.isCall, jsonutil.decodeCall
local _ENV = nil
local defaultOptions = {
}
-- No real default-option handling needed...
local modeOptions = {}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'calls', defaultOptions, mode and modeOptions[mode])
end
--[[
Encodes 'value' as a function call
Must have parameters in the 'callData' field of the metatable
name == name of the function call
parameters == array of parameters to encode
]]
local function getEncoder(options)
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
local function encodeCall(value, state)
if not isCall(value) then
return false
end
local encode = state.encode
local name, params = decodeCall(value)
local compositeEncoder = state.outputEncoder.composite
local valueEncoder = [[
for i = 1, (composite.n or #composite) do
local val = composite[i]
PUTINNER(i ~= 1)
val = encode(val, state)
val = val or ''
if val then
PUTVALUE(val)
end
end
]]
return compositeEncoder(valueEncoder, name .. '(', ')', ',', params, encode, state)
end
return {
table = encodeCall,
['function'] = encodeCall
}
end
local calls = {
mergeOptions = mergeOptions,
getEncoder = getEncoder
}
return calls

View File

@ -0,0 +1,58 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local tostring = tostring
local assert = assert
local jsonutil = require("json.util")
local huge = require("math").huge
local _ENV = nil
local defaultOptions = {
nan = true,
inf = true
}
local modeOptions = {}
modeOptions.strict = {
nan = false,
inf = false
}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode])
end
local function encodeNumber(number, options)
if number ~= number then
assert(options.nan, "Invalid number: NaN not enabled")
return "NaN"
end
if number == huge then
assert(options.inf, "Invalid number: Infinity not enabled")
return "Infinity"
end
if number == -huge then
assert(options.inf, "Invalid number: Infinity not enabled")
return "-Infinity"
end
return tostring(number)
end
local function getEncoder(options)
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
return {
number = function(number, state)
return encodeNumber(number, options)
end
}
end
local number = {
mergeOptions = mergeOptions,
getEncoder = getEncoder
}
return number

View File

@ -0,0 +1,77 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local pairs = pairs
local assert = assert
local type = type
local tostring = tostring
local table_concat = require("table").concat
local jsonutil = require("json.util")
local _ENV = nil
local defaultOptions = {
}
local modeOptions = {}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'object', defaultOptions, mode and modeOptions[mode])
end
--[[
Cleanup function to unmark a value as in the encoding process and return
trailing results
]]
local function unmarkAfterEncode(tab, state, ...)
state.already_encoded[tab] = nil
return ...
end
--[[
Encode a table as a JSON Object ( keys = strings, values = anything else )
]]
local function encodeTable(tab, options, state)
-- Make sure this value hasn't been encoded yet
state.check_unique(tab)
local encode = state.encode
local compositeEncoder = state.outputEncoder.composite
local valueEncoder = [[
local first = true
for k, v in pairs(composite) do
local ti = type(k)
assert(ti == 'string' or ti == 'number' or ti == 'boolean', "Invalid object index type: " .. ti)
local name = encode(tostring(k), state, true)
if first then
first = false
else
name = ',' .. name
end
PUTVALUE(name .. ':')
local val = encode(v, state)
val = val or ''
if val then
PUTVALUE(val)
end
end
]]
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '{', '}', nil, tab, encode, state))
end
local function getEncoder(options)
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
return {
table = function(tab, state)
return encodeTable(tab, options, state)
end
}
end
local object = {
mergeOptions = mergeOptions,
getEncoder = getEncoder
}
return object

View File

@ -0,0 +1,66 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local tostring = tostring
local assert = assert
local jsonutil = require("json.util")
local type = type
local _ENV = nil
-- Shortcut that works
local encodeBoolean = tostring
local defaultOptions = {
allowUndefined = true,
null = jsonutil.null,
undefined = jsonutil.undefined
}
local modeOptions = {}
modeOptions.strict = {
allowUndefined = false
}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
end
local function getEncoder(options)
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
local function encodeOthers(value, state)
if value == options.null then
return 'null'
elseif value == options.undefined then
assert(options.allowUndefined, "Invalid value: Unsupported 'Undefined' parameter")
return 'undefined'
else
return false
end
end
local function encodeBoolean(value, state)
return value and 'true' or 'false'
end
local nullType = type(options.null)
local undefinedType = options.undefined and type(options.undefined)
-- Make sure that all of the types handled here are handled
local ret = {
boolean = encodeBoolean,
['nil'] = function() return 'null' end,
[nullType] = encodeOthers
}
if undefinedType then
ret[undefinedType] = encodeOthers
end
return ret
end
local others = {
encodeBoolean = encodeBoolean,
mergeOptions = mergeOptions,
getEncoder = getEncoder
}
return others

View File

@ -0,0 +1,91 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local type = type
local assert, error = assert, error
local table_concat = require("table").concat
local loadstring = loadstring or load
local io = require("io")
local setmetatable = setmetatable
local output_utility = require("json.encode.output_utility")
local _ENV = nil
local tableCompositeCache = setmetatable({}, {__mode = 'v'})
local TABLE_VALUE_WRITER = [[
ret[#ret + 1] = %VALUE%
]]
local TABLE_INNER_WRITER = ""
--[[
nextValues can output a max of two values to throw into the data stream
expected to be called until nil is first return value
value separator should either be attached to v1 or in innerValue
]]
local function defaultTableCompositeWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
if type(nextValues) == 'string' then
local fun = output_utility.prepareEncoder(defaultTableCompositeWriter, nextValues, innerValue, TABLE_VALUE_WRITER, TABLE_INNER_WRITER)
local ret = {}
fun(composite, ret, encode, state)
return beginValue .. table_concat(ret, innerValue) .. closeValue
end
end
-- no 'simple' as default action is just to return the value
local function getDefault()
return { composite = defaultTableCompositeWriter }
end
-- BEGIN IO-WRITER OUTPUT
local IO_INNER_WRITER = [[
if %WRITE_INNER% then
state.__outputFile:write(%INNER_VALUE%)
end
]]
local IO_VALUE_WRITER = [[
state.__outputFile:write(%VALUE%)
]]
local function buildIoWriter(output)
if not output then -- Default to stdout
output = io.output()
end
local function ioWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
-- HOOK OUTPUT STATE
state.__outputFile = output
if type(nextValues) == 'string' then
local fun = output_utility.prepareEncoder(ioWriter, nextValues, innerValue, IO_VALUE_WRITER, IO_INNER_WRITER)
local ret = {}
output:write(beginValue)
fun(composite, ret, encode, state)
output:write(closeValue)
return nil
end
end
local function ioSimpleWriter(encoded)
if encoded then
output:write(encoded)
end
return nil
end
return { composite = ioWriter, simple = ioSimpleWriter }
end
local function getIoWriter(output)
return function()
return buildIoWriter(output)
end
end
local output = {
getDefault = getDefault,
getIoWriter = getIoWriter
}
return output

View File

@ -0,0 +1,54 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local setmetatable = setmetatable
local assert, loadstring = assert, loadstring or load
local _ENV = nil
-- Key == weak, if main key goes away, then cache cleared
local outputCache = setmetatable({}, {__mode = 'k'})
-- TODO: inner tables weak?
local function buildFunction(nextValues, innerValue, valueWriter, innerWriter)
local putInner = ""
if innerValue and innerWriter then
-- Prepare the lua-string representation of the separator to put in between values
local formattedInnerValue = ("%q"):format(innerValue)
-- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write
putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue)
end
-- Template-in the value writer (if present) and its conditional argument
local functionCode = nextValues:gsub("PUTINNER(%b())", putInner)
-- %VALUE% is to be filled in by the value-to-write
valueWriter = valueWriter:gsub("%%VALUE%%", "%%1")
-- Template-in the value writer with its argument
functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter)
functionCode = [[
return function(composite, ret, encode, state)
]] .. functionCode .. [[
end
]]
return assert(loadstring(functionCode))()
end
local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter)
local cache = outputCache[cacheKey]
if not cache then
cache = {}
outputCache[cacheKey] = cache
end
local fun = cache[nextValues]
if not fun then
fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter)
cache[nextValues] = fun
end
return fun
end
local output_utility = {
prepareEncoder = prepareEncoder
}
return output_utility

View File

@ -0,0 +1,88 @@
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local string_char = require("string").char
local pairs = pairs
local jsonutil = require("json.util")
local util_merge = jsonutil.merge
local _ENV = nil
local normalEncodingMap = {
['"'] = '\\"',
['\\'] = '\\\\',
['/'] = '\\/',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t',
['\v'] = '\\v' -- not in official spec, on report, removing
}
local xEncodingMap = {}
for char, encoded in pairs(normalEncodingMap) do
xEncodingMap[char] = encoded
end
-- Pre-encode the control characters to speed up encoding...
-- NOTE: UTF-8 may not work out right w/ JavaScript
-- JavaScript uses 2 bytes after a \u... yet UTF-8 is a
-- byte-stream encoding, not pairs of bytes (it does encode
-- some letters > 1 byte, but base case is 1)
for i = 0, 255 do
local c = string_char(i)
if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then
-- WARN: UTF8 specializes values >= 0x80 as parts of sequences...
-- without \x encoding, do not allow encoding > 7F
normalEncodingMap[c] = ('\\u%.4X'):format(i)
xEncodingMap[c] = ('\\x%.2X'):format(i)
end
end
local defaultOptions = {
xEncode = false, -- Encode single-bytes as \xXX
processor = nil, -- Simple processor for the string prior to quoting
-- / is not required to be quoted but it helps with certain decoding
-- Required encoded characters, " \, and 00-1F (0 - 31)
encodeSet = '\\"/%z\1-\031',
encodeSetAppend = nil -- Chars to append to the default set
}
local modeOptions = {}
local function mergeOptions(options, mode)
jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
end
local function getEncoder(options)
options = options and util_merge({}, defaultOptions, options) or defaultOptions
local encodeSet = options.encodeSet
if options.encodeSetAppend then
encodeSet = encodeSet .. options.encodeSetAppend
end
local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap
local encodeString
if options.processor then
local processor = options.processor
encodeString = function(s, state)
return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"'
end
else
encodeString = function(s, state)
return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"'
end
end
return {
string = encodeString
}
end
local strings = {
mergeOptions = mergeOptions,
getEncoder = getEncoder
}
return strings