kd2bwzgen

JSON API

Mar 24th, 2018
448
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.04 KB | None | 0 0
  1. -- ElvishJerricco's JSON API adapted for loadfile'ing
  2. -- By MineRobber9000
  3. -- To use: local json = loadfile("json.lua")()
  4. ------------------------------------------------------------------ utils
  5. local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
  6.  
  7. local function isArray(t)
  8. local max = 0
  9. for k,v in pairs(t) do
  10. if type(k) ~= "number" then
  11. return false
  12. elseif k > max then
  13. max = k
  14. end
  15. end
  16. return max == #t
  17. end
  18.  
  19. local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  20. function removeWhite(str)
  21. while whites[str:sub(1, 1)] do
  22. str = str:sub(2)
  23. end
  24. return str
  25. end
  26.  
  27. ------------------------------------------------------------------ encoding
  28.  
  29. local function encodeCommon(val, pretty, tabLevel, tTracking)
  30. local str = ""
  31.  
  32. -- Tabbing util
  33. local function tab(s)
  34. str = str .. ("\t"):rep(tabLevel) .. s
  35. end
  36.  
  37. local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  38. str = str .. bracket
  39. if pretty then
  40. str = str .. "\n"
  41. tabLevel = tabLevel + 1
  42. end
  43. for k,v in iterator(val) do
  44. tab("")
  45. loopFunc(k,v)
  46. str = str .. ","
  47. if pretty then str = str .. "\n" end
  48. end
  49. if pretty then
  50. tabLevel = tabLevel - 1
  51. end
  52. if str:sub(-2) == ",\n" then
  53. str = str:sub(1, -3) .. "\n"
  54. elseif str:sub(-1) == "," then
  55. str = str:sub(1, -2)
  56. end
  57. tab(closeBracket)
  58. end
  59.  
  60. -- Table encoding
  61. if type(val) == "table" then
  62. assert(not tTracking[val], "Cannot encode a table holding itself recursively")
  63. tTracking[val] = true
  64. if isArray(val) then
  65. arrEncoding(val, "[", "]", ipairs, function(k,v)
  66. str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  67. end)
  68. else
  69. arrEncoding(val, "{", "}", pairs, function(k,v)
  70. assert(type(k) == "string", "JSON object keys must be strings", 2)
  71. str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  72. str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  73. end)
  74. end
  75. -- String encoding
  76. elseif type(val) == "string" then
  77. str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  78. -- Number encoding
  79. elseif type(val) == "number" or type(val) == "boolean" then
  80. str = tostring(val)
  81. else
  82. error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
  83. end
  84. return str
  85. end
  86.  
  87. local json={}
  88.  
  89. function json.encode(val)
  90. return encodeCommon(val, false, 0, {})
  91. end
  92.  
  93. function json.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 json.decode(str)
  204. str = removeWhite(str)
  205. t = parseValue(str)
  206. return t
  207. end
  208.  
  209. function json.decodeFromFile(path)
  210. local file = assert(fs.open(path, "r"))
  211. local decoded = json.decode(file.readAll())
  212. file.close()
  213. return decoded
  214. end
  215.  
  216. return json
Advertisement
Add Comment
Please, Sign In to add comment