mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1862 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1862 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
// Originally from /jsonion.gml in JSOnion
 | 
						|
// JSOnion v1.0.0d is licensed under the MIT licence. You may freely adapt and use this library in commercial and non-commercial projects.
 | 
						|
 | 
						|
#define __jso_gmt_tuple
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  tuple(>element_0<, >element_1<, ..., >element_n<): Return an n-tuple
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  //Position, address table and data
 | 
						|
  var pos, addr_table, data;
 | 
						|
  pos = 6*argument_count+4;
 | 
						|
  addr_table = "";
 | 
						|
  data = "";
 | 
						|
  
 | 
						|
  //Build the tuple element-by-element
 | 
						|
  var i, ca, isstr, datastr;
 | 
						|
  for (i=0; i<argument_count; i+=1) {
 | 
						|
    //Check the argument's type
 | 
						|
    ca = argument[i];
 | 
						|
    isstr = is_string(ca);
 | 
						|
    if (isstr) { //Save strings as-is
 | 
						|
      datastr = ca;
 | 
						|
    }
 | 
						|
    else { //Save reals in scientific notation, 15 significant digits
 | 
						|
      datastr = __jso_gmt_numtostr(ca);
 | 
						|
    }
 | 
						|
    //Add entry in address table and data
 | 
						|
    addr_table += chr(isstr+$30)
 | 
						|
    addr_table += string_format(pos, 5, 0);
 | 
						|
    pos += string_length(datastr);
 | 
						|
    data += datastr;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //Return the tuple, with size header character, address table and data
 | 
						|
  return string_format(argument_count, 3, 0)+addr_table+data;
 | 
						|
  
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_elem
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  elem(tuple_source, n): Return the <n>th element of <tuple_source>
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  //Capture arguments
 | 
						|
  var t, n, size;
 | 
						|
  t = argument0;
 | 
						|
  n = argument1;
 | 
						|
  size = __jso_gmt_size(t);
 | 
						|
  
 | 
						|
  //Search for the bounding positions for the <n>th element in the address table
 | 
						|
  var start, afterend, isstr;
 | 
						|
  isstr = ord(string_char_at(t, 4+6*n))-$30;
 | 
						|
  start = real(string_copy(t, 5+6*n, 5));
 | 
						|
  if (n < size-1) {
 | 
						|
    afterend = real(string_copy(t, 11+6*n, 5));
 | 
						|
  } else {
 | 
						|
    afterend = string_length(t)+1;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //Return the <n>th element with the correct type
 | 
						|
  if (isstr) {
 | 
						|
    return string_copy(t, start, afterend-start);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    return real(string_copy(t, start, afterend-start));
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_size
 | 
						|
{
 | 
						|
  
 | 
						|
  /**
 | 
						|
  size(tuple_source): Return the size of <tuple_source>
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  return real(string_copy(argument0, 1, 3));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_numtostr
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  __gmt_numtostr(num): Return string representation of <num>. Decimal numbers expressed as scientific notation
 | 
						|
  with double precision (i.e. 15 digits)
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (edited)
 | 
						|
  */
 | 
						|
  if (frac(argument0) == 0) {
 | 
						|
    return string(argument0);
 | 
						|
  }
 | 
						|
  
 | 
						|
    var mantissa, exponent;
 | 
						|
    exponent = floor(log10(abs(argument0)));
 | 
						|
    mantissa = string_format(argument0/power(10,exponent), 15, 14);
 | 
						|
    var i, ca;
 | 
						|
    i = string_length(mantissa);
 | 
						|
    do {
 | 
						|
      ca = string_char_at(mantissa, i);
 | 
						|
      i -= 1;
 | 
						|
    } until (ca != "0")
 | 
						|
    if (ca != ".") {
 | 
						|
        mantissa = string_copy(mantissa, 1, i+1);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        mantissa = string_copy(mantissa, 1, i);
 | 
						|
    }
 | 
						|
    if (exponent != 0) {
 | 
						|
      return mantissa + "e" + string(exponent);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      return mantissa;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_test_all
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  test_all(): Runs all test suites
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
  
 | 
						|
  //Automated testing sequence
 | 
						|
  __jso_gmt_test_elem();
 | 
						|
  __jso_gmt_test_size();
 | 
						|
  __jso_gmt_test_numtostr();
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_test_numtostr
 | 
						|
{
 | 
						|
  
 | 
						|
  /**
 | 
						|
  _test_numtostr(): Runs number-to-string tests
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  var tolerance;
 | 
						|
  tolerance = 1/10000000000;
 | 
						|
 | 
						|
  if (real(__jso_gmt_numtostr(9)) != 9) {
 | 
						|
    show_message("Scientific notation conversion failed for 1-digit integer! Result: " + __jso_gmt_numtostr(9));
 | 
						|
  }
 | 
						|
  if (real(__jso_gmt_numtostr(500)) != 500) {
 | 
						|
    show_message("Scientific notation conversion failed for 3-digit integer! Result: " + __jso_gmt_numtostr(500));
 | 
						|
  }
 | 
						|
  if (abs(real(__jso_gmt_numtostr(pi))-pi) > tolerance) {
 | 
						|
    show_message("Scientific notation conversion failed for pi! Result: " + __jso_gmt_numtostr(pi));
 | 
						|
  }
 | 
						|
  if (abs(real(__jso_gmt_numtostr(104729.903455))-104729.903455) > tolerance) {
 | 
						|
    show_message("Scientific notation conversion failed for large decimal number! Result: " + __jso_gmt_numtostr(104729.903455));
 | 
						|
  }
 | 
						|
  if (abs(real(__jso_gmt_numtostr(-pi))+pi) > tolerance) {
 | 
						|
    show_message("Scientific notation conversion failed for -pi! Result: " + __jso_gmt_numtostr(-pi));
 | 
						|
  }
 | 
						|
  if (abs(real(__jso_gmt_numtostr(1/pi))-1/pi) > tolerance) {
 | 
						|
    show_message("Scientific notation conversion failed for 1/pi! Result: " + __jso_gmt_numtostr(1/pi));
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_test_elem
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  _test_elem(): Runs tuple element retrieval tests
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  if (__jso_gmt_elem(__jso_gmt_tuple("Qblock", "kll"), 0) != "Qblock") {
 | 
						|
    show_message("Element retrieval failed for simple string. #Should be:Qblock#Actual:" + __jso_gmt_elem(__jso_gmt_tuple("Qblock"), 0));
 | 
						|
  }
 | 
						|
  if (__jso_gmt_elem(__jso_gmt_tuple(9, "Q", -7), 0) != 9) {
 | 
						|
    show_message("Element retrieval failed for simple number. #Should be 9#Actual:" + string(__jso_gmt_elem(__jso_gmt_tuple(9, "Q", 7), 0)));
 | 
						|
  }
 | 
						|
  if (__jso_gmt_elem(__jso_gmt_tuple("Qblock", "", "Negg"), 1) != "") {
 | 
						|
    show_message("Element retrieval failed for empty string#Should be empty string#Actual:"+string(__jso_gmt_elem(__jso_gmt_tuple("Qblock", "", "Negg"), 0)));
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (__jso_gmt_elem(__jso_gmt_elem(__jso_gmt_tuple("Not this", __jso_gmt_tuple(0, 1, 2, 3), "Waahoo"), 1), 3) != 3) {
 | 
						|
    show_message("Element retrieval failed in nested tuple. #Should be 3#Actual:" + string(__jso_gmt_elem(__jso_gmt_elem(__jso_gmt_tuple("Not this", __jso_gmt_tuple(0, 1, 2, 3), "Waahoo"), 1), 3)));
 | 
						|
  }  
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define __jso_gmt_test_size
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
  _test_size(): Runs tuple size tests
 | 
						|
  @author: GameGeisha
 | 
						|
  @version: 1.2 (GMTuple)
 | 
						|
  */
 | 
						|
 | 
						|
  if (__jso_gmt_size(__jso_gmt_tuple("Waahoo", "Negg", 0)) != 3) {
 | 
						|
    show_message("Bad size for 3-tuple");
 | 
						|
  }
 | 
						|
  if (__jso_gmt_size(__jso_gmt_tuple()) != 0) {
 | 
						|
    show_message("Bad size for null tuple");
 | 
						|
  }
 | 
						|
  if (__jso_gmt_size(__jso_gmt_tuple(7)) != 1) {
 | 
						|
    show_message("Bad size for 1-tuple");
 | 
						|
  }
 | 
						|
  if (__jso_gmt_size(__jso_gmt_tuple(1,2,3,4,5,6,7,8,9,10)) != 10) {
 | 
						|
    show_message("Bad size for 10-tuple");
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define jso_new_map
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_new_map(): Create a new map.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return ds_map_create();
 | 
						|
}
 | 
						|
 | 
						|
#define jso_new_list
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_new_list(): Create a new list.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return ds_list_create();
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_real
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_real(map, key, val): Add the key-value pair <key>:<val> to <map>, where <val> is a real value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_map_add(argument0, argument1, argument2);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_string
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_string(map, key, str): Add the key-value pair <key>:<str> to <map>, where <str> is a string value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_map_add(argument0, argument1, "s" + argument2);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_sublist
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_sublist(map, key, sublist): Add the key-value pair <key>:<sublist> to <map>, where <sublist> is a list.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_map_add(argument0, argument1, "l" + string(argument2));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_submap
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_submap(map, key, submap): Add the key-value pair <key>:<submap> to <map>, where <submap> is a map.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_map_add(argument0, argument1, "m" + string(argument2));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_integer
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_integer(map, key, int): Add the key-value pair <key>:<int> to <map>, where <int> is a integer value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_map_add(argument0, argument1, floor(argument2));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_add_boolean
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_add_boolean(map, key, bool): Add the key-value pair <key>:<bool> to <map>, where <bool> is a boolean value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    if (argument2) {
 | 
						|
        ds_map_add(argument0, argument1, "btrue");
 | 
						|
    } else {
 | 
						|
        ds_map_add(argument0, argument1, "bfalse");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_real
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_real(list, val): Append the real value <val> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_list_add(argument0, argument1);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_string
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_string(list, str): Append the string value <str> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_list_add(argument0, "s" + argument1);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_sublist
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_sublist(list, sublist): Append the list <sublist> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_list_add(argument0, "l" + string(argument1));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_submap
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_submap(list, submap): Append the map <submap> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_list_add(argument0, "m" + string(argument1));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_integer
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_integer(list, int): Append the integer <int> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    ds_list_add(argument0, floor(argument1));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_add_boolean
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_add_boolean(list, bool): Append the boolean value <bool> to <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    if (argument1) {
 | 
						|
        ds_list_add(argument0, "btrue");
 | 
						|
    } else {
 | 
						|
        ds_list_add(argument0, "bfalse");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_get
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_get(map, key): Retrieve the value stored in <map> with the key value <key>, with the correct type.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
 | 
						|
    //Grab the value
 | 
						|
    var v;
 | 
						|
    v = ds_map_find_value(argument0, argument1);
 | 
						|
    
 | 
						|
    //String; could be string, map or list
 | 
						|
    if (is_string(v)) {
 | 
						|
        switch (string_char_at(v, 1)) {
 | 
						|
            case "s":
 | 
						|
                return string_delete(v, 1, 1);
 | 
						|
            break;
 | 
						|
            case "l": case "m":
 | 
						|
                return real(string_delete(v, 1, 1));
 | 
						|
            break;
 | 
						|
            case "b":
 | 
						|
                if (v == "btrue") {
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
                else if (v == "bfalse") {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    show_error("Invalid boolean value.", true);
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            default: show_error("Invalid map contents.", true); break;
 | 
						|
        }    
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Real; return real value as-is
 | 
						|
    else {
 | 
						|
        return v;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_get_type
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_get_type(map, key): Return the type of value to which the key value <key> is mapped to in <map>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
 | 
						|
    //Grab the value
 | 
						|
    var v;
 | 
						|
    v = ds_map_find_value(argument0, argument1);
 | 
						|
    
 | 
						|
    //String; could be string, map or list
 | 
						|
    if (is_string(v)) {
 | 
						|
        switch (string_char_at(v, 1)) {
 | 
						|
            case "s":
 | 
						|
                return jso_type_string;
 | 
						|
            break;
 | 
						|
            case "l":
 | 
						|
                return jso_type_list;
 | 
						|
            break;
 | 
						|
            case "m":
 | 
						|
                return jso_type_map;
 | 
						|
            break;
 | 
						|
            case "b":
 | 
						|
                return jso_type_boolean;
 | 
						|
            break;
 | 
						|
            default: show_error("Invalid map content type.", true); break;
 | 
						|
        }    
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Real
 | 
						|
    else {
 | 
						|
        return jso_type_real;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_get
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_get(list, index): Retrieve the value stored in <list> at position <index>, with the correct type.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
 | 
						|
    //Grab the value
 | 
						|
    var v;
 | 
						|
    v = ds_list_find_value(argument0, argument1);
 | 
						|
    
 | 
						|
    //String; could be string, map or list
 | 
						|
    if (is_string(v)) {
 | 
						|
        switch (string_char_at(v, 1)) {
 | 
						|
            case "s":
 | 
						|
                return string_delete(v, 1, 1);
 | 
						|
            break;
 | 
						|
            case "l": case "m":
 | 
						|
                return real(string_delete(v, 1, 1));
 | 
						|
            break;
 | 
						|
            case "b":
 | 
						|
                if (v == "btrue") {
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
                else if (v == "bfalse") {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    show_error("Invalid boolean value.", true);
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            default: show_error("Invalid list contents.", true); break;
 | 
						|
        }    
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Real; return real value as-is
 | 
						|
    else {
 | 
						|
        return v;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_get_type
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_get_type(list, index): Retrieve the type of value found at position <index> of <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Grab the value
 | 
						|
    var v;
 | 
						|
    v = ds_list_find_value(argument0, argument1);
 | 
						|
    
 | 
						|
    //String; could be string, map or list
 | 
						|
    if (is_string(v)) {
 | 
						|
        switch (string_char_at(v, 1)) {
 | 
						|
            case "s":
 | 
						|
                return jso_type_string;
 | 
						|
            break;
 | 
						|
            case "l":
 | 
						|
                return jso_type_list;
 | 
						|
            break;
 | 
						|
            case "m":
 | 
						|
                return jso_type_map;
 | 
						|
            break;
 | 
						|
            case "b":
 | 
						|
                return jso_type_boolean;
 | 
						|
            break;
 | 
						|
            default: show_error("Invalid list content type.", true); break;
 | 
						|
        }    
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Real
 | 
						|
    else {
 | 
						|
        return jso_type_real;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_cleanup_map
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_cleanup_map(map): Recursively free up <map>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Loop through all keys
 | 
						|
    var i, l, k;
 | 
						|
    l = ds_map_size(argument0);
 | 
						|
    k = ds_map_find_first(argument0);
 | 
						|
    for (i=0; i<l; i+=1) {
 | 
						|
    
 | 
						|
        //Look for values that need to be recursed    
 | 
						|
        switch (jso_map_get_type(argument0, k)) {
 | 
						|
            //Maps
 | 
						|
            case jso_type_map:
 | 
						|
                jso_cleanup_map(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
            //Lists
 | 
						|
            case jso_type_list:
 | 
						|
                jso_cleanup_list(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //Find next key
 | 
						|
        k = ds_map_find_next(argument0, k);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Done, clean up
 | 
						|
    ds_map_destroy(argument0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_cleanup_list
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_cleanup_list(list): Recursively free up <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Loop through all elements
 | 
						|
    var i, l, v;
 | 
						|
    l = ds_list_size(argument0);
 | 
						|
    for (i=0; i<l; i+=1) {
 | 
						|
        //Look for elements that need to be recursed
 | 
						|
        switch (jso_list_get_type(argument0, i)) {
 | 
						|
            //Maps
 | 
						|
            case jso_type_map:
 | 
						|
                jso_cleanup_map(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
            //Lists
 | 
						|
            case jso_type_list:
 | 
						|
                jso_cleanup_list(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Done, clean up
 | 
						|
    ds_list_destroy(argument0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_real
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_real(<real>): Return a JSON-encoded version of real value <real>.
 | 
						|
    This uses scientific notation with up to 15 significant digits for decimal values.
 | 
						|
    For integers, it just uses string().
 | 
						|
    This is adapted from the same algorithm used in GMTuple.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    return __jso_gmt_numtostr(argument0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_string
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_string(str): Return a JSON-encoded version of string <str>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Iteratively reconstruct the string
 | 
						|
    var i, l, s, c;
 | 
						|
    s = "";
 | 
						|
    l = string_length(argument0);
 | 
						|
    for (i=1; i<=l; i+=1) {
 | 
						|
        //Replace escape characters
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        switch (ord(c)) {
 | 
						|
            case 34: case 92: case 47: //Double quotes, backslashes and slashes
 | 
						|
                s += "\" + c;
 | 
						|
            break;
 | 
						|
            case 8: //Backspace
 | 
						|
                s += "\b";
 | 
						|
            break;
 | 
						|
            case 12: //Form feed
 | 
						|
                s += "\f";
 | 
						|
            break;
 | 
						|
            case 10: //New line
 | 
						|
                s += "\n";
 | 
						|
            break;
 | 
						|
            case 13: //Carriage return
 | 
						|
                s += "\r";
 | 
						|
            break;
 | 
						|
            case 9: //Horizontal tab
 | 
						|
                s += "\t";
 | 
						|
            break;
 | 
						|
            default: //Not an escape character
 | 
						|
                s += c;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //Add quotes
 | 
						|
    return '"' + s + '"';
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_list
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_list(list): Return a JSON-encoded version of list <list>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Iteratively encode each element
 | 
						|
    var i, l, s;
 | 
						|
    s = "";
 | 
						|
    l = ds_list_size(argument0);
 | 
						|
    for (i=0; i<l; i+=1) {
 | 
						|
        //Prepend comma except for the first element
 | 
						|
        if (i > 0) {
 | 
						|
            s += ",";
 | 
						|
        }
 | 
						|
        //Select correct encoding for each element, then recursively encode each
 | 
						|
        switch (jso_list_get_type(argument0, i)) {
 | 
						|
            case jso_type_real:
 | 
						|
                s += jso_encode_real(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
            case jso_type_string:
 | 
						|
                s += jso_encode_string(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
            case jso_type_map:
 | 
						|
                s += jso_encode_map(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
            case jso_type_list:
 | 
						|
                s += jso_encode_list(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
            case jso_type_boolean:
 | 
						|
                s += jso_encode_boolean(jso_list_get(argument0, i));
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Done, add square brackets
 | 
						|
    return "[" + s + "]";
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_map
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_map(map): Return a JSON-encoded version of map <map>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Go through every key-value pair
 | 
						|
    var i, l, k, s;
 | 
						|
    s = "";
 | 
						|
    l = ds_map_size(argument0);
 | 
						|
    k = ds_map_find_first(argument0);
 | 
						|
    for (i=0; i<l; i+=1) {
 | 
						|
        //Prefix , if there is preceding item
 | 
						|
        if (i > 0) {
 | 
						|
            s += ",";
 | 
						|
        }
 | 
						|
        //Find the key and encode it
 | 
						|
        if (is_real(k)) {
 | 
						|
            s += jso_encode_real(k);
 | 
						|
        } else {
 | 
						|
            s += jso_encode_string(k);
 | 
						|
        }
 | 
						|
        //Add the : separator
 | 
						|
        s += ":";
 | 
						|
        //Select correct encoding for each value, then recursively encode each   
 | 
						|
        switch (jso_map_get_type(argument0, k)) {
 | 
						|
            case jso_type_real:
 | 
						|
                s += jso_encode_real(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
            case jso_type_string:
 | 
						|
                s += jso_encode_string(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
            case jso_type_map:
 | 
						|
                s += jso_encode_map(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
            case jso_type_list:
 | 
						|
                s += jso_encode_list(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
            case jso_type_boolean:
 | 
						|
                s += jso_encode_boolean(jso_map_get(argument0, k));
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        //Get next key
 | 
						|
        k = ds_map_find_next(argument0, k);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Done, add braces
 | 
						|
    return "{" + s + "}";
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_integer
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_integer(int): Return a JSON-encoded version of the integer value <int>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return string(floor(argument0));
 | 
						|
}
 | 
						|
 | 
						|
#define jso_encode_boolean
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_encode_boolean(bool): Return a JSON-encoded version of the boolean value <bool>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    if (argument0) {
 | 
						|
        return "true";
 | 
						|
    } else {
 | 
						|
        return "false";
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_map
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_map(json): Return a JSOnion-compatible map representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_map(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_list
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_list(json): Return a JSOnion-compatible list representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_list(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_string
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_string(json): Return a string representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_string(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_boolean
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_boolean(json): Return a boolean value representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_boolean(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_real
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_real(json): Return a real value representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_real(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define jso_decode_integer
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_decode_integer(json): Return an integer value representing the JSON string <json>.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    return __jso_gmt_elem(_jso_decode_integer(argument0, 1), 0);
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_map
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_map(json, startindex): Extract a map from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted map handle and the position after the ending }.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, map;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    map = jso_new_map();
 | 
						|
    
 | 
						|
    //Seek to first {
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (c != "{") {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
            if (!_jso_is_whitespace_char(c)) && (c != "{") {
 | 
						|
                show_error("Cannot parse map at position " + string(i), true);
 | 
						|
            }
 | 
						|
        } until (c == "{")
 | 
						|
    }
 | 
						|
    i += 1;
 | 
						|
    
 | 
						|
    //Read until end of JSON or ending }
 | 
						|
    var found_end, state, found, current_key;
 | 
						|
    found_end = false;
 | 
						|
    state = 0;
 | 
						|
    for (i=i; i<=len && !found_end; i+=1) {
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        switch (state) {
 | 
						|
            //0: Looking for a key or closing }
 | 
						|
            case 0:
 | 
						|
                switch (c) {
 | 
						|
                    case "}":
 | 
						|
                        found_end = true;
 | 
						|
                    break;
 | 
						|
                    case '"':
 | 
						|
                        found = _jso_decode_string(argument0, i);
 | 
						|
                        current_key = __jso_gmt_elem(found, 0);
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-":
 | 
						|
                        found = _jso_decode_real(argument0, i);
 | 
						|
                        current_key = __jso_gmt_elem(found, 0);
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //1: Looking for the : separator
 | 
						|
            case 1:
 | 
						|
                switch (c) {
 | 
						|
                    case ":":
 | 
						|
                        state = 2;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //2: Looking for a value
 | 
						|
            case 2:
 | 
						|
                switch (c) {
 | 
						|
                    case "[":
 | 
						|
                        found = _jso_decode_list(argument0, i);
 | 
						|
                        jso_map_add_sublist(map, current_key, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 3;
 | 
						|
                    break;
 | 
						|
                    case "{":
 | 
						|
                        found = _jso_decode_map(argument0, i);
 | 
						|
                        jso_map_add_submap(map, current_key, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 3;
 | 
						|
                    break;
 | 
						|
                    case '"':
 | 
						|
                        found = _jso_decode_string(argument0, i);
 | 
						|
                        jso_map_add_string(map, current_key, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 3;
 | 
						|
                    break;
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-":
 | 
						|
                        found = _jso_decode_real(argument0, i);
 | 
						|
                        jso_map_add_real(map, current_key, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 3;
 | 
						|
                    break;
 | 
						|
                    case "t": case "f":
 | 
						|
                        found = _jso_decode_boolean(argument0, i);
 | 
						|
                        jso_map_add_boolean(map, current_key, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 3;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //3: Done looking for an entry, want comma or }
 | 
						|
            case 3:
 | 
						|
                switch (c) {
 | 
						|
                    case "}":
 | 
						|
                        found_end = true;
 | 
						|
                    break;
 | 
						|
                    case ",":
 | 
						|
                        state = 0;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Return extracted map with ending position if the ending } is found
 | 
						|
    if (found_end) {
 | 
						|
        return __jso_gmt_tuple(map, i);
 | 
						|
    }
 | 
						|
    //Ended too early, throw error
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of map in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_list
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_list(json, startindex): Extract a list from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted list handle and the position after the ending ].
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, list;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    list = jso_new_list();
 | 
						|
    
 | 
						|
    //Seek to first [
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (c != "[") {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
            if (!_jso_is_whitespace_char(c)) && (c != "[") {
 | 
						|
                show_error("Cannot parse list at position " + string(i), true);
 | 
						|
            }
 | 
						|
        } until (c == "[")
 | 
						|
    }
 | 
						|
    i += 1;
 | 
						|
    
 | 
						|
    //Read until end of JSON or ending ]
 | 
						|
    var found_end, state, found;
 | 
						|
    found_end = false;
 | 
						|
    state = 0;
 | 
						|
    for (i=i; i<=len && !found_end; i+=1) {
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        switch (state) {
 | 
						|
            //0: Looking for an item
 | 
						|
            case 0:
 | 
						|
                switch (c) {
 | 
						|
                    case "]":
 | 
						|
                        found_end = true;
 | 
						|
                    break;
 | 
						|
                    case "[":
 | 
						|
                        found = _jso_decode_list(argument0, i);
 | 
						|
                        jso_list_add_sublist(list, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    case "{":
 | 
						|
                        found = _jso_decode_map(argument0, i);
 | 
						|
                        jso_list_add_submap(list, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    case '"':
 | 
						|
                        found = _jso_decode_string(argument0, i);
 | 
						|
                        jso_list_add_string(list, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-":
 | 
						|
                        found = _jso_decode_real(argument0, i);
 | 
						|
                        jso_list_add_real(list, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    case "t": case "f":
 | 
						|
                        found = _jso_decode_boolean(argument0, i);
 | 
						|
                        jso_list_add_boolean(list, __jso_gmt_elem(found, 0));
 | 
						|
                        i = __jso_gmt_elem(found, 1)-1;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //1: Done looking for an item, want comma or ]
 | 
						|
            case 1:
 | 
						|
                switch (c) {
 | 
						|
                    case "]":
 | 
						|
                        found_end = true;
 | 
						|
                    break;
 | 
						|
                    case ",":
 | 
						|
                        state = 0;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        if (!_jso_is_whitespace_char(c)) {
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ".", true);
 | 
						|
                        }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Return extracted list with ending position if the ending ] is found
 | 
						|
    if (found_end) {
 | 
						|
        return __jso_gmt_tuple(list, i);
 | 
						|
    }
 | 
						|
    //Ended too early, throw error
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of list in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_string
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_string(json, startindex): Extract a string from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted string and the position after the ending double quote.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, str;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    str = "";
 | 
						|
    
 | 
						|
    //Seek to first double quote
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (c != '"') {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
        } until (c == '"')
 | 
						|
    }
 | 
						|
    i += 1;
 | 
						|
    
 | 
						|
    //Read until end of JSON or ending double quote
 | 
						|
    var found_end, escape_mode;
 | 
						|
    found_end = false;
 | 
						|
    escape_mode = false;
 | 
						|
    for (i=i; i<=len && !found_end; i+=1) {
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        //Escape mode
 | 
						|
        if (escape_mode) {
 | 
						|
            switch (c) {
 | 
						|
                case '"': case "\": case "/":
 | 
						|
                    str += c;
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "b":
 | 
						|
                    str += chr(8);
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "f":
 | 
						|
                    str += chr(12);
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "n":
 | 
						|
                    str += chr(10);
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "r":
 | 
						|
                    str += chr(13);
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "t":
 | 
						|
                    str += chr(9);
 | 
						|
                    escape_mode = false;
 | 
						|
                break;
 | 
						|
                case "u":
 | 
						|
                    var u;
 | 
						|
                    if (len-i < 5) {
 | 
						|
                        show_error("Invalid escape character at position " + string(i) + ".", true);
 | 
						|
                    } else {
 | 
						|
                        str += chr(_jso_hex_to_decimal(string_copy(argument0, i+1, 4)));
 | 
						|
                        escape_mode = false;
 | 
						|
                        i += 4;
 | 
						|
                    }
 | 
						|
                break;
 | 
						|
                default:
 | 
						|
                    show_error("Invalid escape character at position " + string(i) + ".", true);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        //Regular mode
 | 
						|
        else {
 | 
						|
            switch (c) {
 | 
						|
                case '"': found_end = true; break;
 | 
						|
                case "\": escape_mode = true; break;
 | 
						|
                default: str += c; break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Return extracted string with ending position if the ending double quote is found
 | 
						|
    if (found_end) {
 | 
						|
        return __jso_gmt_tuple(str, i);
 | 
						|
    }
 | 
						|
    //Ended too early, throw error
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of string in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_boolean
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_boolean(json, startindex): Extract a boolean from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted boolean and the position after the last e.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, str;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    
 | 
						|
    //Seek to first t or f that can be found
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (c != "t") && (c != "f") {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
            if (!_jso_is_whitespace_char(c)) && (c != "t") && (c != "f") {
 | 
						|
                show_error("Cannot parse boolean value at position " + string(i), true);
 | 
						|
            }
 | 
						|
        } until (c == "t") || (c == "f")
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Look for true if t is found
 | 
						|
    if (c == "t") && (string_copy(argument0, i, 4) == "true") {
 | 
						|
        return __jso_gmt_tuple(true, i+4);
 | 
						|
    }
 | 
						|
    //Look for false if f is found
 | 
						|
    else if (c == "f") && (string_copy(argument0, i, 5) == "false") {
 | 
						|
        return __jso_gmt_tuple(false, i+5);
 | 
						|
    }
 | 
						|
    //Error: unexpected ending
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of boolean in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_real
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_real(json, startindex): Extract a real value from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted real value and the position after the real value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, str;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    str = "";
 | 
						|
    
 | 
						|
    //Seek to first character: +, -, or 0-9
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (string_pos(c, "0123456789+-") == 0) {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
            if (!_jso_is_whitespace_char(c)) && (string_pos(c, "0123456789+-") == 0) {
 | 
						|
                show_error("Cannot parse real value at position " + string(i), true);
 | 
						|
            }
 | 
						|
        } until (string_pos(c, "0123456789+-") > 0)
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Determine starting state
 | 
						|
    var state;
 | 
						|
    switch (c) {
 | 
						|
        case "+": case "-":
 | 
						|
            state = 0;
 | 
						|
        break;
 | 
						|
        default:
 | 
						|
            state = 1;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    str += c;
 | 
						|
    i += 1;
 | 
						|
    
 | 
						|
    //Loop until no more digits found
 | 
						|
    var done;
 | 
						|
    done = false;
 | 
						|
    for (i=i; i<=len && !done; i+=1) {
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        switch (state) {
 | 
						|
            //0: Found a sign, looking for a starting number
 | 
						|
            case 0:
 | 
						|
                switch (c) {
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                        str += c;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //1: Found a starting digit, looking for decimal dot, e, E, or more digits
 | 
						|
            case 1:
 | 
						|
                if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) {
 | 
						|
                    done = true;
 | 
						|
                    i -= 1;
 | 
						|
                } else {
 | 
						|
                    switch (c) {
 | 
						|
                        case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                            str += c;
 | 
						|
                        break;
 | 
						|
                        case ".":
 | 
						|
                            str += c;
 | 
						|
                            state = 2;
 | 
						|
                        break;
 | 
						|
                        case "e": case "E":
 | 
						|
                            str += c;
 | 
						|
                            state = 3;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ", expecting a dot, e, E or a digit.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //2: Found a decimal dot, looking for more digits
 | 
						|
            case 2:
 | 
						|
                switch (c) {
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                        str += c;
 | 
						|
                        state = -2;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //-2: Found a decimal dot and a digit after it, looking for more digits, e, or E
 | 
						|
            case -2:
 | 
						|
                if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) {
 | 
						|
                    done = true;
 | 
						|
                    i -= 1;
 | 
						|
                } else {
 | 
						|
                    switch (c) {
 | 
						|
                        case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                            str += c;
 | 
						|
                        break;
 | 
						|
                        case "e": case "E":
 | 
						|
                            str += c;
 | 
						|
                            state = 3;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ", expecting an e, E or a digit.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //3: Found an e/E, looking for +, - or more digits
 | 
						|
            case 3:
 | 
						|
                switch (c) {
 | 
						|
                    case "+": case "-":
 | 
						|
                        str += c;
 | 
						|
                        state = 4;
 | 
						|
                    break;
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                        str += c;
 | 
						|
                        state = 5;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Unexpected character at position " + string(i) + ", expecting a +, - or a digit.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //4: Found an e/E exponent sign, looking for more digits
 | 
						|
            case 4:
 | 
						|
                switch (c) {
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                        str += c;
 | 
						|
                        state = 5;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //5: Looking for final digits of the exponent
 | 
						|
            case 5:
 | 
						|
                if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) {
 | 
						|
                    done = true;
 | 
						|
                    i -= 1;
 | 
						|
                } else {
 | 
						|
                    switch (c) {
 | 
						|
                        case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                            str += c;
 | 
						|
                            state = 5;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Am I still expecting more characters?
 | 
						|
    if (done) || (state == 1) || (state == -2) || (state == 5) {
 | 
						|
        return __jso_gmt_tuple(real(str), i);
 | 
						|
    }
 | 
						|
    //Error: unexpected ending
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of real in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_decode_integer
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_decode_real(json, startindex): Extract a real value from JSON string <json> starting at position <startindex>.
 | 
						|
    Return a 2-tuple of the extracted integer value (with leading i) and the position after the real value.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var i, len, str;
 | 
						|
    i = argument1;
 | 
						|
    len = string_length(argument0);
 | 
						|
    str = "";
 | 
						|
    
 | 
						|
    //Seek to first character: +, -, or 0-9
 | 
						|
    var c;
 | 
						|
    c = string_char_at(argument0, i);
 | 
						|
    if (string_pos(c, "0123456789+-") == 0) {
 | 
						|
        do {
 | 
						|
            i += 1;
 | 
						|
            c = string_char_at(argument0, i);
 | 
						|
            if (!_jso_is_whitespace_char(c)) && (string_pos(c, "0123456789+-") == 0) {
 | 
						|
                show_error("Cannot parse integer value at position " + string(i), true);
 | 
						|
            }
 | 
						|
        } until (string_pos(c, "0123456789+-") > 0)
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Determine starting state
 | 
						|
    var state;
 | 
						|
    switch (c) {
 | 
						|
        case "+": case "-":
 | 
						|
            state = 0;
 | 
						|
        break;
 | 
						|
        default:
 | 
						|
            state = 1;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    str += c;
 | 
						|
    i += 1;
 | 
						|
    
 | 
						|
    //Loop until no more digits found
 | 
						|
    var done;
 | 
						|
    done = false;
 | 
						|
    for (i=i; i<=len && !done; i+=1) {
 | 
						|
        c = string_char_at(argument0, i);
 | 
						|
        switch (state) {
 | 
						|
            //0: Found a sign, looking for a starting number
 | 
						|
            case 0:
 | 
						|
                switch (c) {
 | 
						|
                    case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                        str += c;
 | 
						|
                        state = 1;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            //1: Found a starting digit, looking for decimal dot, e, E, or more digits
 | 
						|
            case 1:
 | 
						|
                if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) {
 | 
						|
                    done = true;
 | 
						|
                    i -= 1;
 | 
						|
                } else {
 | 
						|
                    switch (c) {
 | 
						|
                        case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":
 | 
						|
                            str += c;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Am I still expecting more characters?
 | 
						|
    if (done) || (state == 1) {
 | 
						|
        return __jso_gmt_tuple(floor(real(str)), i);
 | 
						|
    }
 | 
						|
    //Error: unexpected ending
 | 
						|
    else {
 | 
						|
        show_error("Unexpected end of integer in JSON string.", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define jso_compare_maps
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_compare_maps(map1, map2): Return whether the contents of JSOnion-compatible maps <map1> and <map2> are the same.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //If they aren't the same size, they can't be the same
 | 
						|
    var size;
 | 
						|
    size = ds_map_size(argument0);
 | 
						|
    if (size != ds_map_size(argument1)) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Compare contents pairwise
 | 
						|
    var i, k, type, a, b;
 | 
						|
    k = ds_map_find_first(argument0);
 | 
						|
    for (i=0; i<size; i+=1) {
 | 
						|
        //Check that key exists on both sides
 | 
						|
        if (!ds_map_exists(argument1, k)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        //Check type
 | 
						|
        type = jso_map_get_type(argument0, k);
 | 
						|
        if (jso_map_get_type(argument1, k) != type) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        //Check content
 | 
						|
        a = jso_map_get(argument0, k);
 | 
						|
        b = jso_map_get(argument1, k);
 | 
						|
        switch (type) {
 | 
						|
            case jso_type_map:
 | 
						|
                if (!jso_compare_maps(a, b)) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            case jso_type_list:
 | 
						|
                if (!jso_compare_lists(a, b)) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            default:
 | 
						|
                if (a != b) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        //Advance to next key
 | 
						|
        k = ds_map_find_next(argument0, k);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //No mismatches, return true
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_compare_lists
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_compare_lists(list1, list2): Return whether the contents of JSOnion-compatible lists <list1> and <list2> are the same.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //If they aren't the same size, they can't be the same
 | 
						|
    var size;
 | 
						|
    size = ds_list_size(argument0);
 | 
						|
    if (size != ds_list_size(argument1)) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Compare contents pairwise
 | 
						|
    var i, type, a, b;
 | 
						|
    for (i=0; i<size; i+=1) {
 | 
						|
        //Check type
 | 
						|
        type = jso_list_get_type(argument0, i);
 | 
						|
        if (jso_list_get_type(argument1, i) != type) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        //Check content
 | 
						|
        a = jso_list_get(argument0, i);
 | 
						|
        b = jso_list_get(argument1, i);
 | 
						|
        switch (type) {
 | 
						|
            case jso_type_map:
 | 
						|
                if (!jso_compare_maps(a, b)) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            case jso_type_list:
 | 
						|
                if (!jso_compare_lists(a, b)) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
            default:
 | 
						|
                if (a != b) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //No mismatches, return true
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_check
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_check(map, key1, key2, ...): Recursively look up keys/indices in the top-level map <map>, return whether a value exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_map, 0, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_check
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_check(list, key1, key2, ...): Recursively look up keys/indices in the top-level list <list>, return whether a value exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_list, 0, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_lookup
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_lookup(map, key1, key2, ...): Recursively look up keys/indices in the top-level map <map>, return the value that exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_map, 1, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_map_lookup_type
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_map_lookup_type(map, key1, key2, ...): Recursively look up keys/indices in the top-level map <map>, return the type of value that exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_map, 2, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_lookup
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_lookup(list, key1, key2, ...): Recursively look up keys/indices in the top-level list <list>, return the value that exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_list, 1, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define jso_list_lookup_type
 | 
						|
{
 | 
						|
    /**
 | 
						|
    jso_list_lookup_type(list, key1, key2, ...): Recursively look up keys/indices in the top-level list <list>, return the type of value that exists there.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    //Catch empty calls
 | 
						|
    if (argument_count < 2) {
 | 
						|
        show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Build list of keys/indices
 | 
						|
    var i, key_list;
 | 
						|
    key_list = ds_list_create();
 | 
						|
    for (i=1; i<argument_count; i+=1) {
 | 
						|
        ds_list_add(key_list, argument[i]);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Call lookup kernel and cleanup
 | 
						|
    var result;
 | 
						|
    result = _jso_lookup_kernel(argument[0], jso_type_list, 2, key_list);
 | 
						|
    ds_list_destroy(key_list);
 | 
						|
    
 | 
						|
    //Done
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_lookup_kernel
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_lookup_kernel(jso_ds, jso_type, task_type, ds_args_list): Kernel of the check and lookup functions.
 | 
						|
    - jso_ds: The JSOnion-compatible data structure handle.
 | 
						|
    - jso_type: The type of the JSOnion-compatible (jso_type_list or jso_type_map)
 | 
						|
    - task_type: 0=check, 1=lookup, 2=lookup type
 | 
						|
    - ds_args_list: ds_list of arguments passed in.
 | 
						|
    
 | 
						|
    PLEASE DO NOT CALL DIRECTLY --- use regular jso_*() functions.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    
 | 
						|
    var i, k, data, type, type_string, task_type, keys_size, ds_args_list;
 | 
						|
    data = argument0;
 | 
						|
    type = argument1;
 | 
						|
    if (type == jso_type_map) {
 | 
						|
        type_string = "map";
 | 
						|
    } else {
 | 
						|
        type_string = "list";
 | 
						|
    }
 | 
						|
    task_type = argument2;
 | 
						|
    ds_args_list = argument3;
 | 
						|
    keys_size = ds_list_size(ds_args_list);
 | 
						|
    
 | 
						|
    //Iteratively go through arguments in ds_args_list
 | 
						|
    for (i=0; i<keys_size; i+=1) {
 | 
						|
        k = ds_list_find_value(argument3, i);
 | 
						|
        switch (type) {
 | 
						|
            //Check for existence of the key in the current map
 | 
						|
            case jso_type_map:
 | 
						|
                if (!ds_map_exists(data, k)) {
 | 
						|
                    switch (task_type) {
 | 
						|
                        case 0:
 | 
						|
                            return false;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Cannot find value in " + type_string + " lookup.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                type = jso_map_get_type(data, k);
 | 
						|
                data = jso_map_get(data, k);
 | 
						|
            break;
 | 
						|
            //Check for existence of the index in the current list
 | 
						|
            case jso_type_list:
 | 
						|
                if (is_string(k)) {
 | 
						|
                    switch (task_type) {
 | 
						|
                        case 0:
 | 
						|
                            return false;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Cannot use string indices for nested lists in " + type_string + " lookup.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (k >= ds_list_size(data)) {
 | 
						|
                    switch (task_type) {
 | 
						|
                        case 0:
 | 
						|
                            return false;
 | 
						|
                        break;
 | 
						|
                        default:
 | 
						|
                            show_error("Index overflow for nested lists in " + type_string + " lookup.", true);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                type = jso_list_get_type(data, k);
 | 
						|
                data = jso_list_get(data, k);
 | 
						|
            break;
 | 
						|
            //Trying to go through a leaf; don't attempt to look further
 | 
						|
            default:
 | 
						|
                switch (task_type) {
 | 
						|
                    case 0:
 | 
						|
                        return false;
 | 
						|
                    break;
 | 
						|
                    default:
 | 
						|
                        show_error("Recursive overflow in " + type_string + " lookup.", true);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    //Can find something, return the value requested by the task
 | 
						|
    switch (task_type) {
 | 
						|
        case 0:
 | 
						|
            return true;
 | 
						|
        break;
 | 
						|
        case 1:
 | 
						|
            return data;
 | 
						|
        break;
 | 
						|
        case 2:
 | 
						|
            return type;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_is_whitespace_char
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_is_whitespace_char(char): Return whether <char> is a whitespace character.
 | 
						|
    Definition of whitespace is given by Unicode 6.0, Chapter 4.6.
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    switch (ord(argument0)) {
 | 
						|
        case $0009:
 | 
						|
        case $000A:
 | 
						|
        case $000B:
 | 
						|
        case $000C:
 | 
						|
        case $000D:
 | 
						|
        case $0020:
 | 
						|
        case $0085:
 | 
						|
        case $00A0:
 | 
						|
        case $1680:
 | 
						|
        case $180E:
 | 
						|
        case $2000:
 | 
						|
        case $2001:
 | 
						|
        case $2002:
 | 
						|
        case $2003:
 | 
						|
        case $2004:
 | 
						|
        case $2005:
 | 
						|
        case $2006:
 | 
						|
        case $2007:
 | 
						|
        case $2008:
 | 
						|
        case $2009:
 | 
						|
        case $200A:
 | 
						|
        case $2028:
 | 
						|
        case $2029:
 | 
						|
        case $202F:
 | 
						|
        case $205F:
 | 
						|
        case $3000:
 | 
						|
            return true;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
#define _jso_hex_to_decimal
 | 
						|
{
 | 
						|
    /**
 | 
						|
    _jso_hex_to_decimal(hex_string): Return the decimal value of the hex number represented by <hex_string>
 | 
						|
    JSOnion version: 1.0.0d
 | 
						|
    */
 | 
						|
    var hex_string, hex_digits;
 | 
						|
    hex_string = string_lower(argument0);
 | 
						|
    hex_digits = "0123456789abcdef";
 | 
						|
    
 | 
						|
    //Convert digit-by-digit
 | 
						|
    var i, len, digit_value, num;
 | 
						|
    len = string_length(hex_string);
 | 
						|
    num = 0;
 | 
						|
    for (i=1; i<=len; i+=1) {
 | 
						|
        digit_value = string_pos(string_char_at(hex_string, i), hex_digits)-1;
 | 
						|
        if (digit_value >= 0) {
 | 
						|
            num *= 16;
 | 
						|
            num += digit_value;
 | 
						|
        } 
 | 
						|
        //Unknown character
 | 
						|
        else {
 | 
						|
            show_error("Invalid hex number: " + argument0, true);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return num;
 | 
						|
}
 | 
						|
 |