DavidNorgren

json_decode2

May 14th, 2017
155
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /// json_decode2(json, [objecttypesmap, arraytypesmap])
  2. /// @arg json String to be decoded
  3. /// @arg [objecttypesmap] If a map is supplied, the keys will be set to copies of the loaded maps containing the types of their elements.
  4. /// @arg [arraytypesmap] If a map is supplied, the keys will be set to copies of the loaded lists containing the types of their elements.
  5. ///
  6. /// @desc The string will be decoded into a value/data structure according to the JSON specification at http://www.json.org/.
  7. ////      Objects are translated into ds_maps and arrays into ds_lists. If you destroy the top data structure all below will
  8. ///       automatically be freed as well.
  9. ///
  10. ///       Unlike the built-in function, this will throw a descriptive error whenever an invalid character appears.
  11. ///       This version also supports entering a single value without an enclosing map, for instance json_decode2("12.234")
  12. ///       will return a real number of 12.234, and json_decode2("[1, 2, 3]") will return a single ds_list.
  13. ///       The type of each object/array element in the loaded maps/lists can also be checked by entering two maps into the
  14. ///       objecttypesmap and arraytypesmap arguments. During loading, these maps (if supplied) will be filled using the
  15. ///       e_json_value_type enumerator defined below.
  16. ///
  17. ///       http://www.stuffbydavid.com
  18.  
  19. globalvar json_string, json_token, json_token_queue, json_pos, json_line, json_col,
  20.           json_value, json_value_type, json_object_value_type_map, json_array_value_type_map,
  21.           json_error, json_debug;
  22.  
  23. //json_string = string_replace_all(argument[0], "\r\n", "\n")
  24. json_token = ""
  25. json_token_queue = ds_queue_create()
  26. json_pos = 1
  27. json_line = 1
  28. json_col = 1
  29. json_error = false
  30. json_debug = false
  31.  
  32. if (argument_count > 1)
  33. {
  34.     json_object_value_type_map = argument[1]
  35.     json_array_value_type_map = argument[2]
  36. }
  37. else
  38. {
  39.     json_object_value_type_map = undefined
  40.     json_array_value_type_map = undefined
  41. }
  42.  
  43. // Parse string into queue of tokens
  44. var str, strlen, instring, line, col;
  45. str = argument0
  46. strlen = string_length(str)
  47. line = 1
  48. col = 0
  49. instring = false
  50.  
  51. for (var i = 0; i < strlen; i++)
  52. {
  53.     var char = string_char_at(str, i);
  54.  
  55.     if (char = "\t")
  56.         col += 4
  57.     else
  58.         col++
  59.    
  60.     if (!instring && (char = " " || char = "\t"))
  61.         continue
  62.  
  63.     if (char = "\r" && string_char_at(str, i + 1) = "\n")
  64.     {
  65.         char = "\n"
  66.         i++
  67.     }
  68.    
  69.     if (char = "\n")
  70.     {
  71.         line++
  72.         col = 0
  73.         if (!instring)
  74.             continue
  75.     }
  76.  
  77.     if (char = "\"")
  78.         instring = !instring
  79.  
  80.     var token;
  81.     token[0] = char
  82.     token[1] = line
  83.     token[2] = col
  84.     ds_queue_enqueue(json_token_queue, token)
  85. }
  86.  
  87. // Value types
  88. enum e_json_value_type
  89. {
  90.     OBJECT,
  91.     ARRAY,
  92.     STRING,
  93.     NUMBER,
  94.     BOOL,
  95.     NULL
  96. }
  97.  
  98. // Read root value
  99. if (!json_decode2_value())
  100.     return undefined
  101.    
  102. return json_value
  103.  
  104.  
  105.  
  106. /// json_decode2_value()
  107. /// @desc DO NOT USE DIRECTLY!
  108.  
  109. if (json_debug)
  110.     show_debug_message("json_decode2_value")
  111.  
  112. var next = json_decode2_peek();
  113.  
  114. if (next = "{")
  115.     return json_decode2_object()
  116. else if (next = "[")
  117.     return json_decode2_array()
  118. else if (next = "\"")
  119.     return json_decode2_string()
  120. else if (next = "-" || string_digits(next) != "")
  121.     return json_decode2_number()
  122. else if (next != "")
  123.     return json_decode2_word(next)
  124.    
  125. return false
  126.  
  127.  
  128.  
  129. /// json_decode2_object()
  130. /// @desc DO NOT USE DIRECTLY!
  131.  
  132. if (json_debug)
  133.     show_debug_message("json_decode2_object")
  134.  
  135. if (!json_decode2_next("{"))
  136.     return false
  137.    
  138. var map = ds_map_create();
  139.  
  140. if (!is_undefined(json_object_value_type_map))
  141.     ds_map_add_map(json_object_value_type_map, map, ds_map_create())
  142.  
  143. // Read name/value pairs
  144. while (json_decode2_peek() != "}")
  145. {
  146.     // Read name
  147.     if (!json_decode2_string())
  148.         break
  149.     var name = json_value;
  150.            
  151.     if (!json_decode2_next(":"))
  152.         break
  153.        
  154.     // Read value
  155.     if (!json_decode2_value())
  156.         break
  157.        
  158.     // Add type to map
  159.     if (!is_undefined(json_object_value_type_map))
  160.         ds_map_add(json_object_value_type_map[?map], name, json_value_type)
  161.    
  162.     // Add to map
  163.     switch (json_value_type)
  164.     {
  165.         case e_json_value_type.OBJECT:
  166.             ds_map_add_map(map, name, json_value)
  167.             break
  168.            
  169.         case e_json_value_type.ARRAY:
  170.             ds_map_add_list(map, name, json_value)
  171.             break
  172.            
  173.         default:
  174.             map[?name] = json_value
  175.     }
  176.    
  177.     // No more pairs?
  178.     if (json_decode2_peek() != ",")
  179.         break
  180.        
  181.     json_decode2_next(",")
  182. }
  183.  
  184. if (!json_error)
  185.     json_decode2_next("}")
  186.  
  187. // Clean up on error
  188. if (json_error)
  189. {
  190.     ds_map_destroy(map)
  191.     return false
  192. }
  193.  
  194. json_value = map
  195. json_value_type = e_json_value_type.OBJECT
  196.  
  197. return true
  198.  
  199.  
  200.  
  201. /// json_decode2_array()
  202. /// @desc DO NOT USE DIRECTLY!
  203.  
  204. if (json_debug)
  205.     show_debug_message("json_decode2_array")
  206.  
  207. if (!json_decode2_next("["))
  208.     return false
  209.    
  210. var list = ds_list_create();
  211.  
  212. if (!is_undefined(json_array_value_type_map))
  213.     ds_map_add_list(json_array_value_type_map, list, ds_list_create())
  214.  
  215. // Read values
  216. while (json_decode2_peek() != "]")
  217. {
  218.     // Read value
  219.     if (!json_decode2_value())
  220.         break
  221.    
  222.     // Add to list
  223.     ds_list_add(list, json_value)
  224.    
  225.     // Add type to list
  226.     if (!is_undefined(json_array_value_type_map))
  227.         ds_list_add(json_array_value_type_map[?list], json_value_type)
  228.    
  229.     // Mark type
  230.     switch (json_value_type)
  231.     {
  232.         case e_json_value_type.OBJECT:
  233.             ds_list_mark_as_map(list, ds_list_size(list) - 1)
  234.             break
  235.            
  236.         case e_json_value_type.ARRAY:
  237.             ds_list_mark_as_list(list, ds_list_size(list) - 1)
  238.             break
  239.     }
  240.    
  241.     // No more pairs?
  242.     if (json_decode2_peek() != ",")
  243.         break
  244.        
  245.     json_decode2_next(",")
  246. }
  247.  
  248. if (!json_error)
  249.     json_decode2_next("]")
  250.  
  251. // Clean up on error
  252. if (json_error)
  253. {
  254.     ds_list_destroy(list)
  255.     return false
  256. }
  257.  
  258. json_value = list
  259. json_value_type = e_json_value_type.ARRAY
  260.  
  261. return true
  262.  
  263.  
  264.  
  265. /// json_decode2_string()
  266. /// @desc DO NOT USE DIRECTLY!
  267.  
  268. if (json_debug)
  269.     show_debug_message("json_decode2_string")
  270.  
  271. if (!json_decode2_next("\""))
  272.     return false
  273.    
  274. var str = "";
  275.    
  276. while (true)
  277. {
  278.     var char = string_char_at(json_string, json_pos);
  279.    
  280.     if (char = "\"" || char = "") // End of string/file
  281.         break
  282.        
  283.     json_pos++
  284.     if (char = "\t") // Tab is four spaces
  285.         json_col += 4
  286.     else
  287.         json_col++
  288.        
  289.     if (char = "\\") // Special character
  290.     {
  291.         var next = string_char_at(json_string, json_pos);
  292.        
  293.         if (next = "\"")
  294.             char = "\""
  295.         else if (next = "\\")
  296.             char = "\\"
  297.         else if (next = "/")
  298.             char = "/"
  299.         else if (next = "b")
  300.             char = "\b"
  301.         else if (next = "f")
  302.             char = "\f"
  303.         else if (next = "n")
  304.             char = "\n"
  305.         else if (next = "r")
  306.             char = "\r"
  307.         else if (next = "t")
  308.             char = "\t"
  309.         else
  310.             char += next
  311.            
  312.         json_pos++
  313.         json_col++
  314.     }
  315.     else if (char = "\n") // New line
  316.     {
  317.         json_line++
  318.         json_col = 1
  319.     }
  320.        
  321.     str += char
  322. }
  323.  
  324. if (!json_decode2_next("\""))
  325.     return false
  326.    
  327. json_value = str
  328. json_value_type = e_json_value_type.STRING
  329.  
  330. if (json_debug)
  331.     show_debug_message("json_decode2_string: " + json_value)
  332.  
  333. return true
  334.  
  335.  
  336.  
  337. /// json_decode2_number()
  338. /// @desc DO NOT USE DIRECTLY!
  339.  
  340. if (json_debug)
  341.     show_debug_message("json_decode2_number")
  342.  
  343. var str = "";
  344.  
  345. while (true)
  346. {
  347.     var char = json_decode2_peek();
  348.    
  349.     // We found the end of the number
  350.     if (string_lettersdigits(char) = "" && char != "." && char != "-" && char != "+")
  351.         break
  352.        
  353.     json_decode2_next(char)
  354.     str += char
  355. }
  356.  
  357. json_value = string_get_real(str)
  358. json_value_type = e_json_value_type.NUMBER;
  359.    
  360. if (is_undefined(json_value))
  361. {
  362.     json_decode2_error("Invalid number '" + str + "'")
  363.     return false
  364. }
  365.  
  366. if (json_debug)
  367.     show_debug_message("json_value: " + json_value)
  368.  
  369. return true
  370.  
  371.  
  372.  
  373. /// json_decode2_word(next)
  374. /// @arg next
  375. /// @desc DO NOT USE DIRECTLY!
  376.  
  377. var next = argument0;
  378.  
  379. if (json_debug)
  380.     show_debug_message("json_decode2_other")
  381.  
  382. if (next = "t")
  383. {
  384.     json_decode2_next("t")
  385.     json_decode2_next("r")
  386.     json_decode2_next("u")
  387.     json_decode2_next("e")
  388.     json_value = true
  389.     json_value_type = e_json_value_type.BOOL
  390.     if (json_debug)
  391.         show_debug_message("json_value: true")
  392. }
  393. else if (next = "f")
  394. {
  395.     json_decode2_next("f")
  396.     json_decode2_next("a")
  397.     json_decode2_next("l")
  398.     json_decode2_next("s")
  399.     json_decode2_next("e")
  400.     json_value = false
  401.     json_value_type = e_json_value_type.BOOL
  402.     if (json_debug)
  403.         show_debug_message("json_value: false")
  404. }
  405. else if (next = "n")
  406. {
  407.     json_decode2_next("n")
  408.     json_decode2_next("u")
  409.     json_decode2_next("l")
  410.     json_decode2_next("l")
  411.     json_value = undefined
  412.     json_value_type = e_json_value_type.NULL
  413.     if (json_debug)
  414.         show_debug_message("json_value: null")
  415. }
  416. else
  417.     return json_decode2_error("Unrecognized word")
  418.    
  419. return true
  420.  
  421.  
  422.  
  423. /// json_decode2_peek()
  424. /// @desc DO NOT USE DIRECTLY!
  425. ///       Returns the next token character, "" if EOF
  426.  
  427. return ds_queue_first(json_token_queue)
  428.  
  429.  
  430.  
  431. /// json_decode2_next(expect)
  432. /// @arg expect The expected character
  433. /// @desc DO NOT USE DIRECTLY!
  434.  
  435. var expect, token;
  436. expect = argument0
  437.  
  438. if (json_debug)
  439.     show_debug_message("json_decode2_next, expected: " + expect)
  440.  
  441. if (ds_queue_size() = 0)
  442.     return json_decode2_error("Unexpected end of file")
  443.  
  444. token = ds_queue_dequeue(json_token_queue)
  445.  
  446. if (token[0] != expect)
  447.    return error..
  448.  
  449. return true
  450.  
  451.  
  452.  
  453. /// json_decode2_error(message)
  454. /// @arg message
  455. /// @desc DO NOT USE DIRECTLY!
  456.  
  457. show_message("JSON error: " + argument0 + " at line " + string(json_line) + ", column " + string(json_col))
  458. json_error = true
  459.  
  460. return false
  461.  
  462.  
  463.  
  464. /// string_get_real(string, [invalid]):
  465. /// @arg string
  466. /// @arg [invalid]
  467. /// @desc An acceptable real number takes the following form:
  468. /// [whitespaces] [sign] [digits] [. [digits]] [{e | E} [sign] [digits]] [whitespaces]
  469. /// At least one digit or a decimal point must be present in prior to the exponent part
  470.  
  471. var str, inv, len, state;
  472. str = argument[0]
  473. if (argument_count > 1)
  474.     inv = argument[1]
  475. else
  476.     inv = undefined
  477.  
  478. // Trim white spaces at the end (to make it easier to check the final state)
  479. len = string_length(str)
  480. while (len > 1 && string_char_at(str, len) == " ")
  481.     len--
  482.  
  483. // Now check the string with a state machine
  484. state = 0
  485. for (var i = 1; i <= len; i++)
  486. {
  487.     var c = string_char_at(str, i)
  488.     if (c = " ") // Ignore white spaces at the beginning
  489.     {
  490.         if (state = 0)
  491.             continue
  492.         else
  493.             return inv
  494.     }
  495.     else if (c = "-" || c = "+") // A sign is allowed at the beginning or after 'E'
  496.     {
  497.         if (state = 0 || state = 5)
  498.             state++
  499.         else
  500.             return inv
  501.     }
  502.     else if (ord(c) >= ord("0") && ord(c) <= ord("9")) // A digit is allowed at serveral places...
  503.     {
  504.         if (state <= 2) // At the beginning, after a sign or another digit
  505.             state = 2
  506.         else if (state <= 4) // After a decimal point
  507.             state = 4
  508.         else if (state <= 7) // After an exponent
  509.             state = 7
  510.         else // Not allowed in other places
  511.             return inv
  512.     }
  513.     else if (c = ".") // A decimal point is allowed at the beginning, after a sign or a digit
  514.     {
  515.         if (state <= 2)
  516.             state = 3
  517.         else return inv
  518.     }
  519.     else // No other letters are allowed
  520.     {
  521.         return inv
  522.     }
  523. }
  524.  
  525. // Finally, check that the string ends with at least one digit or a decimal point
  526. if (state >= 2)
  527.     return real(str)
  528. return inv
Advertisement
Add Comment
Please, Sign In to add comment