Under development — the help is being filled in plugin by plugin.
Plugin reference

json

Parse and serialize JSON, with dot-notation path reads.

26 functionsnamespace jsonsource plugins/json/JsonPlugin.c

Written from a line-by-line source review; every example output is from a real run.

Introduction

The json plugin lets you parse, navigate, and build JSON data. It parses a JSON text into an internal tree (Parse), from which you can read values by path, navigate nested objects and arrays, or build a structure from scratch and serialize it to JSON text. The plugin is built on the well-known cJSON library.

A handle-based model

The plugin is handle-based: Parse, NewObject and NewArray return an integer identifier (a handle) that refers to an internal JSON node. Every further operation takes this handle as its first argument. There are two kinds of handle: a ROOT handle (returned by Parse/NewObject/NewArray) owns the whole tree, and Free releases all of it; a SUB-handle (returned by GetObject/GetArray/ArrayGet) refers to a child node and is valid as long as the root lives. Freeing a sub-handle is harmless (it does not break up the tree). IMPORTANT: after the root is freed, its sub-handles also become invalid.

Path syntax

The read functions accept a dot-separated path to an object's members: “user.name”, “config.db.host”. The empty path (“”) means the handle's own node. Array indexing is NOT allowed in the path — for arrays use the GetArray + ArrayGet (then another Get* if needed) combination. A missing path segment (except for HasKey) raises a runtime error.

Type codes (GetType)

GetType returns an integer type code. The values are: 0 = invalid, 1 = false, 2 = true, 4 = null, 8 = number, 16 = string, 32 = array, 64 = object. So for a boolean, true and false get separate codes (2 and 1).

Loading the plugin

plugin "../plugins/print/PrintPlugin";
plugin "../plugins/json/JsonPlugin";

A typical flow — reading

i32 $h;
$h = json.Parse("{\"user\":{\"name\":\"Ada\"}}");
printf("%s\n", json.GetString($h, "user.name"));
json.Free($h);

Error location on malformed JSON

When the parsed JSON is malformed, Parse (and ParseLen) does not merely report that parsing failed — it also tells you the exact location of the error: the line, the column, and the byte offset. Most embedded JSON handlers lack this, yet it greatly helps debugging. For example, for the following input (on line 3 the value after the colon is missing):

json.Parse("{\n \"a\": 1,\n \"b\": ,\n}");

the runtime error message gives the precise location:

json.Parse: parse error at line 3, column 8 (byte 19).

What to know about every function (the basics)

  • json follows strict error handling (like csv/queue): a missing path, a type mismatch (for example GetString on a number), an invalid or already-freed handle, and an out-of-range array index raise a runtime error, and the script stops.

  • HasKey is the exception: for a missing key (or intermediate segment) it returns 0, it does not fail. So use HasKey before reading an uncertain key with Get*.

  • The type must match the function: GetString takes only a string, GetInt/GetDouble only a number, GetBool only a boolean — a mismatch is an error.

  • Set* sets an object's keys (overwriting if the key exists); Add* appends to an array's end. Set* expects an object handle, Add* an array handle.

  • A sub-handle (GetObject/GetArray/ArrayGet) is tied to the root's lifetime; do not use it after the root's Free.

  • The plugin loads the cJSON library with dlopen on first use; if libcjson is not installed, loading still succeeds, but the json.* calls fail.

How to read the signatures

handle is the JSON node's identifier, path is the dot-separated path. The type after the -> arrow is the return type. For example, json.GetInt(handle, path) -> int takes two arguments and returns an integer.

Parsing and freeing

Parsing JSON text into a tree, and freeing the tree.

json.Parse

json.Parse(text) -> int

Parses a JSON text into an internal tree and returns the root handle.

Parameters
Parameter Type Description
text string The JSON text to parse.
Return value

The root handle (a positive integer). Invalid JSON or a full handle registry causes a runtime error; on malformed JSON the message gives the error location (line, column, byte).

Example
i32 $h;
$h = json.Parse("{\"name\":\"Ada\"}");
printf("%s\n", json.GetString($h, "name"));
json.Free($h);
Output after running
Ada
When to use

The first step of processing any JSON data (an API response, a config file, a message). Free the returned handle at the end. On malformed JSON the error message tells you where parsing gave up — for example “parse error at line 3, column 8 (byte 19)” — which greatly helps debugging.

json.ParseLen

json.ParseLen(text, len) -> int

Like Parse, but it parses only the first len bytes of the text.

Parameters
Parameter Type Description
text string The JSON text to parse.
len int The number of bytes to process (cannot be negative).
Return value

The root handle. A negative length, invalid JSON, or a full registry causes a runtime error.

Example
i32 $h;
// parse only the first 8 bytes
$h = json.ParseLen("{\"n\":1} extra", 8);
printf("%d\n", json.GetInt($h, "n"));
json.Free($h);
Output after running
1
When to use

When the JSON is in a larger buffer and you want to process only a given-length part (for example the start of a network message), without a copy.

json.Free

json.Free(handle) -> int

Frees the handle. For a root, the whole tree; for a sub-handle, only the script-level identifier (the tree is untouched).

Parameters
Parameter Type Description
handle int The handle to free.
Return value

Always 1.

Example
i32 $h;
$h = json.Parse("{}");
printf("%d\n", json.Free($h));
Output after running
1
When to use

Always free the root handle when you are done, so the tree's memory is released. After freeing the root, do not use the sub-handles obtained from it.

Reading (values)

Reading a value by path. The type must match the function (apart from HasKey, every mismatch/absence is an error).

json.GetType

json.GetType(handle, path) -> int

Gives the type of the node at the path as an integer type code.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path (empty = the handle itself).
Return value

The type code: 1=false, 2=true, 4=null, 8=number, 16=string, 32=array, 64=object.

Example
i32 $h;
$h = json.Parse("{\"user\":{},\"tags\":[]}");
printf("%d\n", json.GetType($h, "user"));
printf("%d\n", json.GetType($h, "tags"));
json.Free($h);
Output after running
64
32
When to use

When you do not know a field's type in advance and want to pick the matching Get*. It is worth putting the type codes into named constants in the script for readability.

json.GetString

json.GetString(handle, path) -> string

Reads the string value at the path.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path.
Return value

The string value. If the node is not a string (or the path is missing), a runtime error.

Example
i32 $h;
$h = json.Parse("{\"user\":{\"name\":\"Ada\"}}");
printf("%s\n", json.GetString($h, "user.name"));
json.Free($h);
Output after running
Ada
When to use

For reading text fields. If you are not sure the key exists or is a string, check first with HasKey or GetType.

json.GetInt

json.GetInt(handle, path) -> int

Reads the number at the path as an integer.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path.
Return value

The integer value. If the node is not a number (or the path is missing), a runtime error.

Example
i32 $h;
$h = json.Parse("{\"user\":{\"age\":36}}");
printf("%d\n", json.GetInt($h, "user.age"));
json.Free($h);
Output after running
36
When to use

For reading integers (age, count, identifier). For a fractional value, GetDouble is the right one.

json.GetDouble

json.GetDouble(handle, path) -> double

Reads the number at the path as a floating-point (double) value.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path.
Return value

The floating-point value. If the node is not a number (or the path is missing), a runtime error.

Example
i32 $h;
$h = json.Parse("{\"ratio\":0.5}");
printf("%f\n", json.GetDouble($h, "ratio"));
json.Free($h);
Output after running
0.500000
When to use

For reading fractional numbers (a ratio, a price, a measurement). JSON does not distinguish integer from fractional, so pick the Get* that fits your purpose.

json.GetBool

json.GetBool(handle, path) -> int

Reads the boolean value at the path.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path.
Return value

1 if true; 0 if false. If the node is not a boolean (or the path is missing), a runtime error.

Example
i32 $h;
$h = json.Parse("{\"user\":{\"admin\":true}}");
printf("%d\n", json.GetBool($h, "user.admin"));
json.Free($h);
Output after running
1
When to use

For reading logical flags (enabled, active, admin). With GetType you can tell a missing value apart from an explicit false, if that matters.

json.HasKey

json.HasKey(handle, path) -> int

Tells whether the key at the path exists. The only read function that does not fail on a missing key.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path.
Return value

1 if the key exists; 0 if not (or if an intermediate segment is missing).

Example
i32 $h;
$h = json.Parse("{\"user\":{\"name\":\"Ada\"}}");
printf("%d\n", json.HasKey($h, "user.name"));
printf("%d\n", json.HasKey($h, "user.xxx"));
json.Free($h);
Output after running
1
0
When to use

For a safe check before Get* calls, to avoid a runtime error from a missing key on optional fields.

Navigation (objects and arrays)

Accessing nested objects and arrays through sub-handles.

json.GetObject

json.GetObject(handle, path) -> int

Returns a sub-handle to the nested object at the path.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path to the nested object.
Return value

A sub-handle to the object. If the node is not an object (or is missing), a runtime error.

Example
i32 $h;
i32 $sub;
$h = json.Parse("{\"user\":{\"name\":\"Ada\"}}");
$sub = json.GetObject($h, "user");
printf("%s\n", json.GetString($sub, "name"));
json.Free($h);
Output after running
Ada
When to use

For navigating a deeply nested structure: branch into the sub-object once, then read on from there with a shorter path. The sub-handle is valid for the root's lifetime.

json.GetArray

json.GetArray(handle, path) -> int

Returns a sub-handle to the array at the path.

Parameters
Parameter Type Description
handle int The JSON node's handle.
path string The dot-separated path to the array.
Return value

A sub-handle to the array. If the node is not an array (or is missing), a runtime error.

Example
i32 $h;
i32 $arr;
$h = json.Parse("{\"tags\":[\"x\",\"y\",\"z\"]}");
$arr = json.GetArray($h, "tags");
printf("%d\n", json.ArrayLength($arr));
json.Free($h);
Output after running
3
When to use

For accessing arrays, since the path cannot index an array. Walk the returned handle with ArrayLength and ArrayGet.

json.ArrayLength

json.ArrayLength(arrayHandle) -> int

Gives the number of elements of an array handle.

Parameters
Parameter Type Description
arrayHandle int A handle to an array (returned by GetArray or ArrayGet).
Return value

The number of elements. If the handle is not an array, a runtime error.

Example
i32 $h;
i32 $arr;
$h = json.Parse("{\"tags\":[\"x\",\"y\",\"z\"]}");
$arr = json.GetArray($h, "tags");
printf("%d\n", json.ArrayLength($arr));
json.Free($h);
Output after running
3
When to use

For iterating over the array: from 0 to ArrayLength-1, with each element given by ArrayGet.

json.ArrayGet

json.ArrayGet(arrayHandle, index) -> int

Returns a sub-handle to the array element at the given index.

Parameters
Parameter Type Description
arrayHandle int A handle to an array.
index int The element's 0-based index.
Return value

A sub-handle to the element. If the handle is not an array or the index is out of range, a runtime error.

Example
i32 $h;
i32 $arr;
i32 $elem;
$h = json.Parse("{\"tags\":[\"x\",\"y\",\"z\"]}");
$arr = json.GetArray($h, "tags");
$elem = json.ArrayGet($arr, 1);
// empty path = the element itself
printf("%s\n", json.GetString($elem, ""));
json.Free($h);
Output after running
y
When to use

For accessing one element of the array. The element itself can be an object or array — on the returned sub-handle you continue with the matching Get*/GetObject/GetArray. Read a scalar element with an empty path (“”).

Building objects

Creating a new object and setting its keys. Set* expects an object handle and overwrites if the key already exists.

json.NewObject

json.NewObject() -> int

Creates a new, empty JSON object and returns the root handle.

Parameters

This function takes no arguments.

Return value

The root handle of the new object.

Example
i32 $o;
$o = json.NewObject();
json.SetString($o, "name", "Bob");
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"name":"Bob"}
When to use

The first step of building a JSON object (an API request body, a config, a response). At the end you turn it into text with Serialize and free it with Free.

json.SetString

json.SetString(obj, key, val) -> int

Sets a string-valued key on the object.

Parameters
Parameter Type Description
obj int An object handle.
key string The key name.
val string The text to set.
Return value

Always 1.

Example
i32 $o;
$o = json.NewObject();
json.SetString($o, "name", "Bob");
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"name":"Bob"}
When to use

For adding a text field. If the key already exists, it is overwritten — so you can also update an existing value with it.

json.SetInt

json.SetInt(obj, key, val) -> int

Sets an integer-valued key on the object.

Parameters
Parameter Type Description
obj int An object handle.
key string The key name.
val int The integer to set.
Return value

Always 1.

Example
i32 $o;
$o = json.NewObject();
json.SetInt($o, "age", 41);
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"age":41}
When to use

For adding an integer field (count, identifier, age).

json.SetDouble

json.SetDouble(obj, key, val) -> int

Sets a floating-point-valued key on the object.

Parameters
Parameter Type Description
obj int An object handle.
key string The key name.
val double The floating-point value to set.
Return value

Always 1.

Example
i32 $o;
$o = json.NewObject();
json.SetDouble($o, "score", 9.5);
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"score":9.5}
When to use

For adding a fractional field (a price, a ratio, a measurement).

json.SetBool

json.SetBool(obj, key, val) -> int

Sets a boolean-valued key on the object.

Parameters
Parameter Type Description
obj int An object handle.
key string The key name.
val int 0 = false, anything else = true.
Return value

Always 1.

Example
i32 $o;
$o = json.NewObject();
json.SetBool($o, "active", 1);
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"active":true}
When to use

For adding a logical flag. 0 maps to false, every other value to true.

json.SetNull

json.SetNull(obj, key) -> int

Sets a null-valued key on the object.

Parameters
Parameter Type Description
obj int An object handle.
key string The key name.
Return value

Always 1.

Example
i32 $o;
$o = json.NewObject();
json.SetNull($o, "note");
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"note":null}
When to use

For signaling an explicit null value (for example “the field exists but has no value”), distinguished from the key being absent entirely.

Building arrays

Creating a new array and appending elements. Add* expects an array handle and appends to the array's end.

json.NewArray

json.NewArray() -> int

Creates a new, empty JSON array and returns the root handle.

Parameters

This function takes no arguments.

Return value

The root handle of the new array.

Example
i32 $a;
$a = json.NewArray();
json.AddInt($a, 7);
printf("%s\n", json.Serialize($a));
json.Free($a);
Output after running
[7]
When to use

The first step of building a JSON array. You append elements with the Add* functions, then Serialize + Free at the end.

json.AddString

json.AddString(arr, val) -> int

Appends a string value to the end of the array.

Parameters
Parameter Type Description
arr int An array handle.
val string The text to append.
Return value

Always 1.

Example
i32 $a;
$a = json.NewArray();
json.AddString($a, "alpha");
printf("%s\n", json.Serialize($a));
json.Free($a);
Output after running
["alpha"]
When to use

For adding a text element to an array (a list of tags, names, lines).

json.AddInt

json.AddInt(arr, val) -> int

Appends an integer value to the end of the array.

Parameters
Parameter Type Description
arr int An array handle.
val int The integer to append.
Return value

Always 1.

Example
i32 $a;
$a = json.NewArray();
json.AddInt($a, 7);
printf("%s\n", json.Serialize($a));
json.Free($a);
Output after running
[7]
When to use

For adding an integer element (a list of identifiers, numeric values).

json.AddDouble

json.AddDouble(arr, val) -> int

Appends a floating-point value to the end of the array.

Parameters
Parameter Type Description
arr int An array handle.
val double The floating-point value to append.
Return value

Always 1.

Example
i32 $a;
$a = json.NewArray();
json.AddDouble($a, 1.5);
printf("%s\n", json.Serialize($a));
json.Free($a);
Output after running
[1.5]
When to use

For adding a fractional element (a measurement series, a list of ratios).

json.AddBool

json.AddBool(arr, val) -> int

Appends a boolean value to the end of the array.

Parameters
Parameter Type Description
arr int An array handle.
val int 0 = false, anything else = true.
Return value

Always 1.

Example
i32 $a;
$a = json.NewArray();
json.AddBool($a, 0);
printf("%s\n", json.Serialize($a));
json.Free($a);
Output after running
[false]
When to use

For adding a logical element. 0 maps to false, every other value to true.

Serializing

Turning the JSON tree into text in compact or indented form.

json.Serialize

json.Serialize(handle) -> string

Turns the JSON tree under the handle into compact (single-line, no spaces) JSON text.

Parameters
Parameter Type Description
handle int The handle of the node to serialize.
Return value

The compact JSON text.

Example
i32 $o;
$o = json.NewObject();
json.SetString($o, "name", "Bob");
json.SetInt($o, "age", 41);
printf("%s\n", json.Serialize($o));
json.Free($o);
Output after running
{"name":"Bob","age":41}
When to use

For transmitting or storing data where size matters (network, file). The compact form is the shortest.

json.SerializePretty

json.SerializePretty(handle) -> string

Turns the JSON tree under the handle into human-readable, indented (formatted) JSON text.

Parameters
Parameter Type Description
handle int The handle of the node to serialize.
Return value

The indented JSON text.

Example
i32 $o;
$o = json.NewObject();
json.SetString($o, "name", "Bob");
json.SetInt($o, "age", 41);
printf("%s\n", json.SerializePretty($o));
json.Free($o);
Output after running
{
"name": "Bob",
"age": 41
}
When to use

For human-readable output: a log, debugging, a config file. Longer because of the indentation, but more legible than the compact form.

Practical notes

What the json plugin is good for

  • Reading API responses and config files, and getting values out by path.

  • Navigating nested structures (an object within an object, arrays) through sub-handles.

  • Building output JSON from scratch (a request body, a response, a message), then turning it into text.

  • Emitting data in compact (network) or indented (readable) form.

Reading safely

Since the Get* functions raise a runtime error both for a missing key and for a type mismatch, check optional or uncertain fields first with HasKey (existence) and GetType (type). You can read required, well-known fields directly — there an error precisely signals bad input.

Handle lifetime

The root handle (Parse/NewObject/NewArray) is freed by Free, together with the whole tree. The sub-handles (GetObject/GetArray/ArrayGet) are tied to the root's lifetime: after the root is freed they can no longer be used. In a long-running script, close every root with Free so the handle registry does not run out.

Common pitfalls

  • An array in the path: the path can only navigate object members; an array needs GetArray + ArrayGet.

  • Type mismatch: GetString on a number (or vice versa) is an error — use GetType first if the type is uncertain.

  • Stale handle: after the root's Free, the sub-handles obtained from it are invalid.

  • Missing libcjson: if cJSON is not installed on the system, the json.* calls fail (while loading still succeeds).

Error handling

A wrong argument count or type, a missing path, a type mismatch, an invalid or stale handle, an out-of-range array index, and bad JSON input are reported by the runtime as a runtime error, and the script stops. On malformed JSON the Parse and ParseLen message gives the exact error location (line, column, and byte offset), which makes it easier to find the broken part in the input. HasKey is the only read function that signals a missing key not as an error but with a 0 return value — so use it to check optional fields.

The sqlite database plugin

A thin wrapper over the SQLite C-API — complete function reference