1--[[ 2 Licensed according to the included 'LICENSE' document 3 Author: Thomas Harning Jr <harningt@gmail.com> 4]] 5local setmetatable = setmetatable 6local assert, loadstring = assert, loadstring or load 7 8local _ENV = nil 9 10-- Key == weak, if main key goes away, then cache cleared 11local outputCache = setmetatable({}, {__mode = 'k'}) 12-- TODO: inner tables weak? 13 14local function buildFunction(nextValues, innerValue, valueWriter, innerWriter) 15 local putInner = "" 16 if innerValue and innerWriter then 17 -- Prepare the lua-string representation of the separator to put in between values 18 local formattedInnerValue = ("%q"):format(innerValue) 19 -- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write 20 putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue) 21 end 22 -- Template-in the value writer (if present) and its conditional argument 23 local functionCode = nextValues:gsub("PUTINNER(%b())", putInner) 24 -- %VALUE% is to be filled in by the value-to-write 25 valueWriter = valueWriter:gsub("%%VALUE%%", "%%1") 26 -- Template-in the value writer with its argument 27 functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter) 28 functionCode = [[ 29 return function(composite, ret, encode, state) 30 ]] .. functionCode .. [[ 31 end 32 ]] 33 return assert(loadstring(functionCode))() 34end 35 36local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter) 37 local cache = outputCache[cacheKey] 38 if not cache then 39 cache = {} 40 outputCache[cacheKey] = cache 41 end 42 local fun = cache[nextValues] 43 if not fun then 44 fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter) 45 cache[nextValues] = fun 46 end 47 return fun 48end 49 50local output_utility = { 51 prepareEncoder = prepareEncoder 52} 53 54return output_utility 55