Expressions

Expression are given in a simple Python- or JavaScript-like expression language. Its data types are limited to JSON types plus function objects.

Literals

Literals are similar to those for JSON. Numeric literals only accept integer and decimal notation. Strings do not support any kind of escaping. The use of \n and \t in the example below depends on the YAML parser to expand the escapes.

template:
  - {$eval: "1.3"}
  - {$eval: "'abc'"}
  - {$eval: '"abc"'}
  - {$eval: "'\n\t'"}
context: {}
result:
  - 1.3
  - "abc"
  - "abc"
  - "\n\t"

Array and object literals also look much like JSON, with bare identifiers allowed as keys like in Javascript:

template:
  - {$eval: '[1, 2, "three"]'}
  - {$eval: '{foo: 1, "bar": 2}'}
context: {}
result:
  - [1, 2, "three"]
  - {"foo": 1, "bar": 2}

Context References

Bare identifiers refer to items from the context or to built-ins (described below).

template: {$eval: '[x, z, x+z]'}
context: {x: 'quick', z: 'sort'}
result: ['quick', 'sort', 'quicksort']

Arithmetic Operations

The usual arithmetic operators are all defined, with typical associativity and precedence:

template:
  - {$eval: 'x + z'}
  - {$eval: 's + t'}
  - {$eval: 'z - x'}
  - {$eval: 'x * z'}
  - {$eval: 'z / x'}
  - {$eval: 'z ** 2'}
  - {$eval: '(z / x) ** 2'}
context: {x: 10, z: 20, s: "face", t: "plant"}
result:
  - 30
  - "faceplant"
  - 10
  - 200
  - 2
  - 400
  - 4

Note that strings can be concatenated with +, but none of the other operators apply.

Comparison Operations

Comparisons work as expected. Equality is "deep" in the sense of doing comparisons of the contents of data structures.

template:
  - {$eval: 'x < z'}
  - {$eval: 'x <= z'}
  - {$eval: 'x > z'}
  - {$eval: 'x >= z'}
  - {$eval: 'deep == [1, [3, {a: 5}]]'}
  - {$eval: 'deep != [1, [3, {a: 5}]]'}
context: {x: -10, z: 10, deep: [1, [3, {a: 5}]]}
result: [true, true, false, false, true, false]

Boolean Operations

Boolean operations use C- and Javascript-style symbols ||, &&, and !:

template: {$eval: '!(false || false) && true'}
context: {}
result: true

Json-e supports short-circuit evaluation, so if in || left operand is true returning value will be true no matter what right operand is:

template: {$eval: "true || b"}
context: {}
result: true

And if in && left operand is false returning value will be false no matter what right operand is:

template: {$eval: "false && b"}
context: {}
result: false

Object Property Access

Like Javascript, object properties can be accessed either with array-index syntax or with dot syntax. Unlike Javascript, obj.prop is an error if obj does not have prop, while obj['prop'] will evaluate to null.

template: {$eval: 'v.a + v["b"]'}
context: {v: {a: 'apple', b: 'bananna', c: 'carrot'}}
result: 'applebananna'

Indexing and Slicing

Strings and arrays can be indexed and sliced using a Python-like indexing scheme. Negative indexes are counted from the end of the value. Slices are treated as "half-open", meaning that the result contains the first index and does not contain the second index. A "backward" slice with the start index greater than the end index is treated as empty.

template:
  - {$eval: '[array[1], string[1]]'}
  - {$eval: '[array[1:4], string[1:4]]'}
  - {$eval: '[array[2:], string[2:]]'}
  - {$eval: '[array[:2], string[:2]]'}
  - {$eval: '[array[4:2], string[4:2]]'}
  - {$eval: '[array[-2], string[-2]]'}
  - {$eval: '[array[-2:], string[-2:]]'}
  - {$eval: '[array[:-3], string[:-3]]'}
context: {array: ['a', 'b', 'c', 'd', 'e'], string: 'abcde'}
result:
  - ['b', 'b']
  - [['b', 'c', 'd'], 'bcd']
  - [['c', 'd', 'e'], 'cde']
  - [['a', 'b'], 'ab']
  - [[], '']
  - ['d', 'd']
  - [['d', 'e'], 'de']
  - [['a', 'b'], 'ab']

Containment Operation

The in keyword can be used to check for containment: a property in an object, an element in an array, or a substring in a string.

template:
  - {$eval: '"foo" in {foo: 1, bar: 2}'}
  - {$eval: '"foo" in ["foo", "bar"]'}
  - {$eval: '"foo" in "foobar"'}
context: {}
result: [true, true, true]

Function Invocation

Function calls are made with the usual fn(arg1, arg2) syntax. Functions are not JSON data, so they cannot be created in JSON-e, but they can be provided as built-ins or supplied in the context and called from JSON-e.