This class provides methods for parsing and generating JavaScript Object Notation (JSON).
Words in italics indicate an instance of a class. The word corresponds to the class name, except where more than one instance is represented in the same statement. In that case a number (2, 3, etc.) is appended to the class name.
Words in normal typeface are to be taken literally (required punctuation, class name in a static reference, method name, etc.)
The symbol => is used to separate an expression (on the left) from its return value (on the right).
An ellipsis (...) indicates that the previous argument may be repeated any number of times. The description will indicate whether one instance is required.
new json() => json
new json(mapper) => json
json.AddMapper(mapper)
json.applyExponent(decimal, int) => decimal
json.Default => json
new json(), but is provided for the convenience of using it where
the "new" keyword is not syntactically valid.
json.emit(object) => string
Produces a string representing object as JSON, using json's Mappers.
json.escape(a) => string
Escapes special characters within a for use in JSON, returning the fully escaped string. The following characters are escaped:
| Character | Hexadecimal | Escape sequence |
|---|---|---|
| BS | 08 | \b |
| TAB | 09 | \t |
| LF | 0A | \n |
| FF | 0C | \f |
| CR | 0D | \r |
| " | 22 | \" |
| / | 2F | \/ |
| \ | 5C | \\ |
| Other control characters, and DEL | 00-07,0B,0E-1F,7F | \u00XX, where XX is the hexadecimal character value |
You do not need to call this routine before calling emit. It will be called automatically when generating string values and object names. If you override emit in a Mapper, however, then you will need to call escape for any object name or string value you generate.
json.parse(a) => object
Parses the JSON contained in a and produces a Synergy/DE object that represents it, based on json's Mappers.
If the parser encounters syntax that isn't recognized as valid JSON, a ParserException will be thrown.
json.unescape(a) => string
Replaces JSON escape sequences in a with their proper characters, returning the converted string. The escapes replaced match those listed under the escape method. Note that Unicode escapes for character values greater than 127 (hex 7F) will not result in the desired character. Synergy/DE does not use Unicode, so only the low-order 8 bits will be treated as ASCII instead.
You do not need to call this method in conjunction with parse. It will be called automatically for string values and object names.
new json.Bool(boolean) => bool
This class wraps boolean values for use in JSON, because booleans in Synergy/DE
are easily confused with integers. The DefaultMapper's
emit method will
emit a Bool as either true or false, rather than its numeric value. Conversely,
the parse method will create a Bool when it encounters
true or false as a value, so you can tell that the value was boolean rather than a
number. Use (obj .is. json.Bool) to determine that it is a Bool.
This class takes its truth value as the only argument to its constructor. It mixes in boolean so you can use the object in any test for truth or falsehood, without casting it. It also mixes in comparable, so you can compare a Bool against another Bool or a boolean. Furthermore, Bool overrides object.Equals to compare equality with Bool, Var (using Var's truth value), or @boolean.
This class overrides object.ToString() to generate "true" or "false".
This class is the base for JSON <-> object mappers. A Mapper converts JSON to Synergy/DE objects and vice versa. A default mapper is provided by the DefaultMapper class.
If you derive your own Mapper, you do not need to provide mapping for all objects. Any method that is not overridden invokes the corresponding method on its Next member. Likewise, if your method does not know how to handle a particular object, it can call the parent method to invoke the method on the next Mapper. This allows you to add more than one Mapper to a json parser/emitter to handle different classes of object. By default, the last Mapper in the chain is the DefaultMapper.
The Mapper class has the following public members:
mapper.addElement(object, object2)
Next.addElement(object, object2)
mapper.addPair(object, a, object2)
Next.addPair(object, a, object2)
mapper.booleanValue(boolean) => object
Next.booleanValue(boolean)
mapper.createArray() => object
Next.createArray()
mapper.createObject() => object
Next.createObject()
mapper.emit(json, object) => string
This method must produce a string containing the JSON that represents object.
If a Mapper does not wish to assume responsibility for generating JSON for the class
of object, it should
call parent.emit(json, object). If the emission
includes other objects (i.e., if this object represents a JSON object or array), then
to generate the JSON for those component objects it should call
json.emit(object2), rather than generating it inline
or recursing to this method. That allows any mapper that has been inserted before
this one to have the first crack at generating each object's JSON.
The base class calls Next.emit(json, object)
mapper.Next => mapper2
mapper.Next = mapper2
mapper.nullValue() => object
Next.nullValue()
mapper.numberValue(decimal, int) => object
json.applyExponent(decimal, int), which may result
in an overflow or underflow. This method provides both arguments so you have the option
of storing greater precision than decimal affords. If you do not wish to override the
DefaultMapper representation of number values,
you should not implement this method. The base class calls
Next.numberValue(decimal, int)
mapper.stringValue(a) => object
Next.stringValue(a)
This class provides default JSON <-> object mapping. Its emit method translates the following Synergy/DE classes to JSON components:
| Legend |
|---|
| Not available on .NET |
| Available on all platforms |
| Synergy/DE class | JSON component |
|---|---|
| ^null | null |
| ArrayList (includes ls) | array |
| @boolean | true/false |
| @byte | number |
| @d | number |
| @decimal | number |
| Hash | object |
| @i | number |
| @int | number |
| json.Bool | true/false |
| json.Null | null |
| @long | number |
| @sbyte | number |
| @short | number |
| VarDec | number |
| VarInt | number |
| anything else | string (using Object.ToString()) |
Where a class is listed as "not available on .NET" that is because we cannot interrogate those types in Synergy/DE on .NET, so they are converted to strings. For cross-platform code, stick to the options that are available on all platforms.
Null presents another interesting case. You can have an ArrayList member that is ^null, but setting a Hash member to ^null is equivalent to deleting it. So if you want the JSON to specify null for the value of a pair in an object, use json.Null.instance instead of ^null.
Hashes are emitted as objects in {}, specifying key/value pairs as "name": value, separated by commas (with a maximum name length of 1024 characters). The emit method calls json.emit for each value, so if you provide your own mapper you can still use this mapper to represent objects as Hashes while doing your own mapping for other classes if you choose. Hashes should be CaseSensitive, or every name will be uppercase.
ArrayLists are emitted as arrays in [], with each member emitted as a value, separated by commas. The emit method calls json.emit for each value.
JSON elements map to Synergy/DE objects as follows:
| JSON component | Synergy/DE class |
|---|---|
| array | ls |
| false | json.Bool |
| null | json.Null |
| number | VarDec |
| object | Hash |
| string | VarAlpha |
| true | json.Bool |
DefaultMapper uses the cross-platform compatible options for numbers and boolean values. Null also translates to json.Null instead of ^null, because otherwise you would not be able to see it in a Hash. Hashes created by DefaultMapper are always case-sensitive.
json.Null.instance => null
This class is used to stand in for ^null, because Hash
members that are null are treated as unspecified. To test whether an object
is a Null, use the Synergy/DE .is. operator: (obj .is. json.Null).
This class mixes in the Singleton pattern, so there is
only one instance. You can access it as json.Null.instance.
This class of exception will be thrown whenever the parse or unescape methods encounter invalid JSON syntax. The Message property will begin with "JSON Parsing error: ", followed by a more detailed description:
| Message | Explanation |
|---|---|
| colon expected | An object name was not followed by a colon |
| Exponent expected | A number was followed by e or E, but nothing else |
| Four digits required for Unicode escape | \u was followed by less than four characters |
| Invalid numeric format | A number contained a character that was not 0-9, ., e, E, + or -, or it contained more than one e or E |
| string must begin with " | An object name (within {}) did not begin with a quote |
| Unescaped \ at end of string | A string value or object name ended with '\'. |
| Unexpected end of string | The end of the string was reached before all required tokens |
| Unrecognized hex unicode value | The four characters following \u were not all valid hex digits (0-9,A-F,a-f) |
| Unrecognized value | A value did not begin with {, [, ", -, or 0-9, and it was not true, false, or null. |