antonsavov

WIP json

Jan 2nd, 2018
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.00 KB | None | 0 0
  1. -------------------------------
  2. -- /lib/json
  3. -------------------------------
  4. --- A collection of utiltity functions to handle JSON objects
  5.  
  6. ------------------------------------------------------------------ utils
  7. local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
  8.  
  9. local function isArray(t)
  10.     local max = 0
  11.     for k,v in pairs(t) do
  12.         if type(k) ~= "number" then
  13.             return false
  14.         elseif k > max then
  15.             max = k
  16.         end
  17.     end
  18.     return max == #t
  19. end
  20.  
  21. local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  22. function removeWhite(str)
  23.     while whites[str:sub(1, 1)] do
  24.         str = str:sub(2)
  25.     end
  26.     return str
  27. end
  28.  
  29. ------------------------------------------------------------------ encoding
  30.  
  31. local function encodeCommon(val, pretty, tabLevel, tTracking)
  32.     local str = ""
  33.  
  34.     -- Tabbing util
  35.     local function tab(s)
  36.         str = str .. ("\t"):rep(tabLevel) .. s
  37.     end
  38.  
  39.     local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  40.         str = str .. bracket
  41.         if pretty then
  42.             str = str .. "\n"
  43.             tabLevel = tabLevel + 1
  44.         end
  45.         for k,v in iterator(val) do
  46.             tab("")
  47.             loopFunc(k,v)
  48.             str = str .. ","
  49.             if pretty then str = str .. "\n" end
  50.         end
  51.         if pretty then
  52.             tabLevel = tabLevel - 1
  53.         end
  54.         if str:sub(-2) == ",\n" then
  55.             str = str:sub(1, -3) .. "\n"
  56.         elseif str:sub(-1) == "," then
  57.             str = str:sub(1, -2)
  58.         end
  59.         tab(closeBracket)
  60.     end
  61.  
  62.     -- Table encoding
  63.     if type(val) == "table" then
  64.         assert(not tTracking[val], "Cannot encode a table holding itself recursively")
  65.         tTracking[val] = true
  66.         if isArray(val) then
  67.             arrEncoding(val, "[", "]", ipairs, function(k,v)
  68.                 str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  69.             end)
  70.         else
  71.             arrEncoding(val, "{", "}", pairs, function(k,v)
  72.                 assert(type(k) == "string", "JSON object keys must be strings", 2)
  73.                 str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  74.                 str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  75.             end)
  76.         end
  77.     -- String encoding
  78.     elseif type(val) == "string" then
  79.         str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  80.     -- Number encoding
  81.     elseif type(val) == "number" or type(val) == "boolean" then
  82.         str = tostring(val)
  83.     else
  84.         error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
  85.     end
  86.     return str
  87. end
  88.  
  89. function encode(val)
  90.     return encodeCommon(val, false, 0, {})
  91. end
  92.  
  93. function encodePretty(val)
  94.     return encodeCommon(val, true, 0, {})
  95. end
  96.  
  97. ------------------------------------------------------------------ decoding
  98.  
  99. local decodeControls = {}
  100. for k,v in pairs(controls) do
  101.     decodeControls[v] = k
  102. end
  103.  
  104. function parseBoolean(str)
  105.     if str:sub(1, 4) == "true" then
  106.         return true, removeWhite(str:sub(5))
  107.     else
  108.         return false, removeWhite(str:sub(6))
  109.     end
  110. end
  111.  
  112. function parseNull(str)
  113.     return nil, removeWhite(str:sub(5))
  114. end
  115.  
  116. local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
  117. function parseNumber(str)
  118.     local i = 1
  119.     while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
  120.         i = i + 1
  121.     end
  122.     local val = tonumber(str:sub(1, i - 1))
  123.     str = removeWhite(str:sub(i))
  124.     return val, str
  125. end
  126.  
  127. function parseString(str)
  128.     str = str:sub(2)
  129.     local s = ""
  130.     while str:sub(1,1) ~= "\"" do
  131.         local next = str:sub(1,1)
  132.         str = str:sub(2)
  133.         assert(next ~= "\n", "Unclosed string")
  134.  
  135.         if next == "\\" then
  136.             local escape = str:sub(1,1)
  137.             str = str:sub(2)
  138.  
  139.             next = assert(decodeControls[next..escape], "Invalid escape character")
  140.         end
  141.  
  142.         s = s .. next
  143.     end
  144.     return s, removeWhite(str:sub(2))
  145. end
  146.  
  147. function parseArray(str)
  148.     str = removeWhite(str:sub(2))
  149.  
  150.     local val = {}
  151.     local i = 1
  152.     while str:sub(1, 1) ~= "]" do
  153.         local v = nil
  154.         v, str = parseValue(str)
  155.         val[i] = v
  156.         i = i + 1
  157.         str = removeWhite(str)
  158.     end
  159.     str = removeWhite(str:sub(2))
  160.     return val, str
  161. end
  162.  
  163. function parseObject(str)
  164.     str = removeWhite(str:sub(2))
  165.  
  166.     local val = {}
  167.     while str:sub(1, 1) ~= "}" do
  168.         local k, v = nil, nil
  169.         k, v, str = parseMember(str)
  170.         val[k] = v
  171.         str = removeWhite(str)
  172.     end
  173.     str = removeWhite(str:sub(2))
  174.     return val, str
  175. end
  176.  
  177. function parseMember(str)
  178.     local k = nil
  179.     k, str = parseValue(str)
  180.     local val = nil
  181.     val, str = parseValue(str)
  182.     return k, val, str
  183. end
  184.  
  185. function parseValue(str)
  186.     local fchar = str:sub(1, 1)
  187.     if fchar == "{" then
  188.         return parseObject(str)
  189.     elseif fchar == "[" then
  190.         return parseArray(str)
  191.     elseif tonumber(fchar) ~= nil or numChars[fchar] then
  192.         return parseNumber(str)
  193.     elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
  194.         return parseBoolean(str)
  195.     elseif fchar == "\"" then
  196.         return parseString(str)
  197.     elseif str:sub(1, 4) == "null" then
  198.         return parseNull(str)
  199.     end
  200.     return nil
  201. end
  202.  
  203. function decode(str)
  204.     str = removeWhite(str)
  205.     t = parseValue(str)
  206.     return t
  207. end
  208.  
  209. function decodeFromFile(path)
  210.     local file = assert(fs.open(path, "r"))
  211.     local decoded = decode(file.readAll())
  212.     file.close()
  213.     return decoded
  214. end
Add Comment
Please, Sign In to add comment