diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 959c200a..f8de1cf6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,4 +1,19 @@ -Jsone (2021-11-17) +Jsone 4.5.0 (2022-12-25) +======================== + +Features +-------- + +- Added a $default case to the switch operator (#455) + + +Improved Documentation +---------------------- + +- Replaced the documentation site with a new, more usable and ineractive version + + +Jsone 4.4.3 (2021-11-17) =================== Features @@ -7,6 +22,9 @@ Features - The JSON-e GitHub repository has been moved to https://github.com/json-e/json-e. (#430) +Jsone 4.4.2 (2021-11-12) +=================== + Bugfixes -------- diff --git a/js/package.json b/js/package.json index 7670342e..ef830e82 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "json-e", - "version": "4.4.3", + "version": "4.5.0", "description": "json parameterization module inspired from json-parameterization", "main": "./src/index.js", "browser": "./dist/index.js", diff --git a/py/jsone/newsfragments/455.feature b/py/jsone/newsfragments/455.feature deleted file mode 100644 index fee4e6d5..00000000 --- a/py/jsone/newsfragments/455.feature +++ /dev/null @@ -1 +0,0 @@ -Added a $default case to the switch operator \ No newline at end of file diff --git a/py/setup.py b/py/setup.py index 92a8a23c..2ac134e1 100644 --- a/py/setup.py +++ b/py/setup.py @@ -2,7 +2,7 @@ import os from setuptools import setup, find_packages -version = "4.4.3" +version = "4.5.0" description='A data-structure parameterization system written for embedding context in JSON objects' diff --git a/rs/Cargo.lock b/rs/Cargo.lock index 000e32ed..88d352b2 100644 --- a/rs/Cargo.lock +++ b/rs/Cargo.lock @@ -53,7 +53,7 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "json-e" -version = "4.4.3" +version = "4.5.0" dependencies = [ "anyhow", "chrono", diff --git a/rs/Cargo.toml b/rs/Cargo.toml index b19582cc..200f835e 100644 --- a/rs/Cargo.toml +++ b/rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "json-e" -version = "4.4.3" +version = "4.5.0" authors = ["owlishDeveloper ", "Alex Lopez "] edition = "2018" license = "MPL-2.0" diff --git a/rs/specification.yml b/rs/specification.yml new file mode 100644 index 00000000..5e6c894f --- /dev/null +++ b/rs/specification.yml @@ -0,0 +1,5396 @@ +################################################################################ +# ### Specification for json-e +# This document specifies the json-e template language through a series of +# test cases on the form: `{title, context, template, result, error, panic}` +# where `jsone.render(template, context) = result` and title is short name +# for the test case. If the `error` property is specified as `true`, no result +# needs to be specified, as the test case must throw an error. If the `panic` +# property is specified as `true`, the test case is expected to throw an error +# about invalid usage, typically invalid context. +# +# Comments explaining the test cases is encouraged, additionally entries with +# {section: '...'} is encouraged to separate sections. +# +# Test conditions: +# 1) Time at test time is expected to be '2017-01-19T16:27:20.974Z' +################################################################################ +--- +section: Initial Minimal Subset +--- +title: Identity +context: {} +template: {key: [1,2,{key2: 'val', key3: 1}, true], f: false} +result: {key: [1,2,{key2: 'val', key3: 1}, true], f: false} +--- +title: fromNow +context: {} +template: {$fromNow: ''} +result: '2017-01-19T16:27:20.974Z' +--- +title: fromNow 2 days 3 hours +context: {} +template: {$fromNow: '2 days 3 hours'} +result: '2017-01-21T19:27:20.974Z' +--- +title: $eval without context +context: {} +template: {$eval: '1 + 2'} +result: 3 +--- +title: $eval +context: {key: ['value', 1, 2, true, {}]} +template: {$eval: 'key'} +result: ['value', 1, 2, true, {}] +--- +title: $json +context: {} +template: {$json: [1,2,true,{},[]]} +result: '[1,2,true,{},[]]' +--- +title: $json alphabetical +context: {} +template: {$json: {'Z':null,'q':1,'a':{'c':45,'b':['9',8,{}]},'r':true}} +result: '{"Z":null,"a":{"b":["9",8,{}],"c":45},"q":1,"r":true}' +--- +title: string interpolation +context: {key: 'world', num: 1} +template: {message: 'hello ${key}', 'k-${num}': true} +result: {message: 'hello world', 'k-1': true} +--- +title: string interpolation with object evaluation +context: {key: 'world', num: 1} +template: {message: 'hello ${{a: "world"}.a}', 'k-${{a: 1}.a + {a: 0}.a}': true} +result: {message: 'hello world', 'k-1': true} +--- +title: multiple string interpolation (1) +context: {a: 'hello', b: 'world'} +template: {message: '${a} ${b}'} +result: {message: 'hello world'} +--- +title: multiple string interpolation (2) +context: {a: 'hello', b: 'world'} +template: {message: '${a}$$${b}'} +result: {message: 'hello$${b}'} +--- +title: multiple string interpolation (3) +context: {a: 'hello', b: 'world'} +template: {message: '${a}##${b}'} +result: {message: 'hello##world'} +--- +title: string interpolation escapes +context: {} +template: {message: 'a literal $${in a string}'} +result: {message: 'a literal ${in a string}'} +--- +title: string interpolation escapes with more $ +context: {x: 'a'} +template: ['${x}', '$${x}', '$$${x}', '$$$${x}', '$$$$${x}'] +result: ['a', '${x}', '$${x}', '$$${x}', '$$$${x}'] +--- +title: string interpolation of keys +context: {name: 'foo', value: 'bar'} +template: {"tc_${name}": "${value}"} +result: {"tc_foo": "bar"} +--- +title: string interpolation with unbalanced } +context: {} +template: {message: 'tricky ${"}}}}"}'} +result: {message: 'tricky }}}}'} +--- +title: can't interpolate arrays +context: {key: [1,2,3]} +template: {message: 'hello ${key}'} +error: "TemplateError at template.message: interpolation of 'key' produced an array or object" +--- +title: can't interpolate objects +context: {key: {}} +template: 'hello ${key}' +error: "TemplateError: interpolation of 'key' produced an array or object" +--- +title: booleans interpolate +context: {t: true, f: false} +template: '${t} or ${f}: yeast is a bacterium' +result: 'true or false: yeast is a bacterium' +--- +title: numbers interpolate +context: {round: 3, decimal: 3.75} +template: '${round}, really ${decimal}' +result: '3, really 3.75' +--- +title: nulls interpolate +context: {nothing: null} +template: 'big pile of ${nothing}' +result: 'big pile of ' +--- +title: invalid context +context: {'a b c': 1} +template: {} +error: 'TemplateError: top level keys of context must follow /[a-zA-Z_][a-zA-Z0-9_]*/' +panic: true +################################################################################ +--- +section: $if operator +--- +title: $if-then-else, true +context: {cond: true} +template: {$if: 'cond', then: 1, else: 2} +result: 1 +--- +title: $if-then-else, false +context: {cond: false} +template: {$if: 'cond', then: 1, else: 2} +result: 2 +--- +title: $if-then in array, true +context: {cond: true} +template: [0, {$if: 'cond', then: 1}] +result: [0, 1] +--- +title: $if-then in array, false +context: {cond: false} +template: [0, {$if: 'cond', then: 1}] +result: [0] # missing else branch should return a delete-marker +--- +title: $if-then in object, true +context: {cond: true} +template: {key: {$if: 'cond', then: 1}, k2: 3} +result: {key: 1, k2: 3} +--- +title: $if-then in object, false +context: {cond: false} +template: {key: {$if: 'cond', then: 1}, k2: 3} +result: {k2: 3} # missing else branch should return a delete-marker +--- +title: $if -> delete-marker, true +context: {cond: true} +template: {key: {$if: 'cond'}, k2: 3} +result: {k2: 3} # missing then/else branches should return a delete-marker +--- +title: $if -> delete-marker, false +context: {cond: false} +template: {key: {$if: 'cond'}, k2: 3} +result: {k2: 3} # missing then/else branches should return a delete-marker +--- +title: $if->then, then => $eval, true +context: {key: {b: 1}} +template: {$if: 'true', then: {$eval: 'key'}} +result: {b: 1} +--- +title: $if->else, else => $eval, false +context: {key: {b: 1}} +template: {$if: 'false', else: {$eval: 'key'}} +result: {b: 1} +--- +title: $if->then, then => ${}, true +context: {key: 'one'} +template: {$if: 'true', then: '${key}'} +result: 'one' +--- +title: $if->else, else => ${}, false +context: {key: 'one'} +template: {$if: 'false', else: '${key}'} +result: 'one' +--- +title: $if->then, then => object, true +context: {cond: true} +template: {$if: 'cond', then: {key: 'hello world'}} +result: {key: 'hello world'} +--- +title: $if->else, else => object, false +context: {cond: false} +template: {$if: 'cond', else: {key: 'hello world'}} +result: {key: 'hello world'} +--- +title: $if->then, then => object, $eval, true +context: {cond: true, key: 'hello world'} +template: {$if: 'cond', then: {key: {$eval: 'key'}}} +result: {key: 'hello world'} +--- +title: $if->else, else => object, $eval, false +context: {cond: false, key: 'hello world'} +template: {$if: 'cond', else: {key: {$eval: 'key'}}} +result: {key: 'hello world'} +--- +title: $if->then, then => object, interpolation, true +context: {cond: true, key: 'world'} +template: {$if: 'cond', then: {key: 'hello ${key}'}} +result: {key: 'hello world'} +--- +title: $if->else, else => object, interpolation, false +context: {cond: false, key: 'world'} +template: {$if: 'cond', else: {key: 'hello ${key}'}} +result: {key: 'hello world'} +--- +title: $if->then->else, empty string +context: {cond: "", key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: f +--- +title: $if->then->else, nonempty string +context: {cond: "stuff", key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: t +--- +title: $if->then->else, string "0" # once upon a time, this was false in PHP.. maybe still is +context: {cond: "0", key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: t +--- +title: $if->then->else, zero +context: {cond: 0, key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: f +--- +title: $if->then->else, one +context: {cond: 1, key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: t +--- +title: $if->then->else, null +context: {cond: null, key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: f +--- +title: $if->then->else, empty array +context: {cond: [], key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: f +--- +title: $if->then->else, nonempty array +context: {cond: [1, 2], key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: t +--- +title: $if->then->else, empty object +context: {cond: {}, key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: f +--- +title: $if->then->else, nonempty object +context: {cond: {a: 2}, key: 'world'} +template: {$if: 'cond', then: "t", else: "f"} +result: t +--- +title: $if->then->else, function +context: {} +template: {$if: 'min', then: "t", else: "f"} +result: t +--- +title: $if->then evaluating to nothing at the top level is null +context: {cond: false} +template: {$if: 'cond', then: "t"} +result: null +--- +title: $if-then-else with undefined properties +context: {cond: true} +template: {$if: 'cond', then: 1, foo: 'bar', else: 2, bing: 'baz'} +error: 'TemplateError: $if has undefined properties: bing foo' +################################################################################ +--- +section: escape operators +--- +title: escape $eval +context: {} +template: {$$eval: "1+2"} +result: {$eval: "1+2"} +--- +title: escape $flatten +context: {} +template: {$$flatten: [[1, 2], [3, 4], [5]]} +result: {$flatten: [[1, 2], [3, 4], [5]]} +--- +title: escape $fromNow +context: {} +template: {$$fromNow: "2 days"} +result: {$fromNow: "2 days"} +--- +title: escape $if +context: {} +template: {$$if: false} +result: {$if: false} +--- +title: escape $json +context: {} +template: {$$json: [1, 2, 3]} +result: {$json: [1, 2, 3]} +--- +title: escape $let +context: {} +template: {$$let: {ts: 100, foo: 200}, in: [{$$eval: "ts+foo"}]} +result: {$let: {ts: 100, foo: 200}, in: [{$eval: "ts+foo"}]} +--- +title: escape $map +context: {} +template: {$$map: [2, 4, 6], each(x): {$$eval: "x + a"}} +result: {$map: [2, 4, 6], each(x): {$eval: "x + a"}} +--- +title: escape $match +context: {x: 1} +template: {$$match: [{'x == 1': 2}]} +result: {$match: [{'x == 1': 2}]} +--- +title: escape $switch +context: {x: 1} +template: {$$switch: [{'x == 1': 2}]} +result: {$switch: [{'x == 1': 2}]} +--- +title: escape $merge +context: {} +template: {$$merge: [{a: 1}, {a: 2}]} +result: {$merge: [{a: 1}, {a: 2}]} +--- +title: escape $reverse +context: {} +template: {$$reverse: [3, 2, 1]} +result: {$reverse: [3, 2, 1]} +--- +title: escape $sort +context: {} +template: {$$sort: [3, 2, 1]} +result: {$sort: [3, 2, 1]} +--- +title: reserved $-keywords +context: {} +template: {$nothing: 1} +error: 'TemplateError: $ is reserved; use $$' +--- +title: escape non-json-e operator +context: {} +template: {$$nothing: 1} +result: {$nothing: 1} +################################################################################ +--- +section: $flatten +--- +title: simple flatten +context: {} +template: {$flatten: [[1, 2], [3, 4], [5]]} +result: [1, 2, 3, 4, 5] +--- +title: flatten empty array +context: {} +template: {$flatten: []} +result: [] +--- +title: flatten empty array of arrays +context: {} +template: {$flatten: [[]]} +result: [] +--- +title: flatten evaluated value +context: {} +template: {$flatten: {$eval: '[[1], [2, 3]]'}} +result: [1, 2, 3] +--- +title: flatten null +context: {} +template: {$flatten: null} +error: 'TemplateError: $flatten value must evaluate to an array' +--- +title: flatten an object +context: {} +template: {$flatten: {a: 1, b: 2}} +error: 'TemplateError: $flatten value must evaluate to an array' +--- +title: flatten an array of strings +context: {} +template: {$flatten: ["a", "b"]} +result: ["a", "b"] +--- +title: flatten an array of numbers +context: {} +template: {$flatten: [1, 2]} +result: [1, 2] +--- +title: flatten mixed types +context: {} +template: {$flatten: [[1, 2], [['a', 'b']], [{}], [[]]]} +result: [1, 2, ['a', 'b'], {}, []] +--- +title: flatten mixed levels +context: {} +template: {$flatten: [[1, [2, 3]], [4], 5]} +result: [1, [2, 3], 4, 5] +--- +title: flatten with undefined properties +context: {} +template: {$flatten: {$eval: '[[1], [2, 3]]'}, foo: 'bar'} +error: 'TemplateError: $flatten has undefined properties: foo' +################################################################################ +--- +section: $flattenDeep +--- +title: simple flattenDeep +context: {} +template: {$flattenDeep: [[1, [2, [3]]]]} +result: [1, 2, 3] +--- +title: flattenDeep empty array +context: {} +template: {$flattenDeep: []} +result: [] +--- +title: evaluated value +context: {} +template: {$flattenDeep: {$eval: '[[1], [2, [3]]]'}} +result: [1, 2, 3] +--- +title: flattenDeep empty array of arrays +context: {} +template: {$flattenDeep: [[]]} +result: [] +--- +title: flattenDeep null +context: {} +template: {$flattenDeep: null} +error: 'TemplateError: $flattenDeep value must evaluate to an array' +--- +title: flattenDeep an object +context: {} +template: {$flattenDeep: {a: 1, b: 2}} +error: 'TemplateError: $flattenDeep value must evaluate to an array' +--- +title: flattenDeep an array of strings +context: {} +template: {$flattenDeep: ["a", "b"]} +result: ["a", "b"] +--- +title: flattenDeep an array of numbers +context: {} +template: {$flattenDeep: [1, 2]} +result: [1, 2] +--- +title: flattenDeep mixed types +context: {} +template: {$flattenDeep: [[1, 2], [['a', 'b']], [{}], [[]]]} +result: [1, 2, 'a', 'b', {}] +--- +title: flattenDeep mixed levels +context: {} +template: {$flattenDeep: [[1, [2, 3]], [4], 5]} +result: [1, 2, 3, 4, 5] +--- +title: flattenDeep with undefined properties +context: {} +template: {$flattenDeep: [[1, [2, 3]], [4], 5], foo: 'bar'} +error: 'TemplateError: $flattenDeep has undefined properties: foo' +################################################################################ +--- +section: $fromNow +--- +title: $fromNow 1 hour +context: {} +template: {$fromNow: '1 hour'} +result: '2017-01-19T17:27:20.974Z' +--- +title: $fromNow 2 hours +context: {} +template: {$fromNow: '2 hours'} +result: '2017-01-19T18:27:20.974Z' +--- +title: $fromNow 3h +context: {} +template: {$fromNow: '3h'} +result: '2017-01-19T19:27:20.974Z' +--- +title: $fromNow 1 hours +context: {} +template: {$fromNow: '1 hours'} +result: '2017-01-19T17:27:20.974Z' +--- +title: $fromNow -1 hour +context: {} +template: {$fromNow: '-1 hour'} +result: '2017-01-19T15:27:20.974Z' +--- +title: $fromNow 1 m +context: {} +template: {$fromNow: '1 m'} +result: '2017-01-19T16:28:20.974Z' +--- +title: $fromNow 1m +context: {} +template: {$fromNow: '1m'} +result: '2017-01-19T16:28:20.974Z' +--- +title: $fromNow 12 min +context: {} +template: {$fromNow: '12 min'} +result: '2017-01-19T16:39:20.974Z' +--- +title: $fromNow 12min +context: {} +template: {$fromNow: '12min'} +result: '2017-01-19T16:39:20.974Z' +--- +title: $fromNow 11m +context: {} +template: {$fromNow: '11m'} +result: '2017-01-19T16:38:20.974Z' +--- +title: $fromNow 11 m +context: {} +template: {$fromNow: '11 m'} +result: '2017-01-19T16:38:20.974Z' +--- +title: $fromNow 1 day +context: {} +template: {$fromNow: '1 day'} +result: '2017-01-20T16:27:20.974Z' +--- +title: $fromNow 2 days +context: {} +template: {$fromNow: '2 days'} +result: '2017-01-21T16:27:20.974Z' +--- +title: $fromNow 1 second +context: {} +template: {$fromNow: '1 second'} +result: '2017-01-19T16:27:21.974Z' +--- +title: $fromNow 1 week +context: {} +template: {$fromNow: '1 week'} +result: '2017-01-26T16:27:20.974Z' +--- +title: $fromNow 1 month +context: {} +template: {$fromNow: '1 month'} +result: '2017-02-18T16:27:20.974Z' +--- +title: $fromNow 30 mo +context: {} +template: {$fromNow: '30 mo'} +result: '2019-07-08T16:27:20.974Z' +--- +title: $fromNow -30 mo +context: {} +template: {$fromNow: '-30 mo'} +result: '2014-08-03T16:27:20.974Z' +--- +title: $fromNow 1 year +context: {} +template: {$fromNow: '1 year'} +result: '2018-01-19T16:27:20.974Z' +--- +title: $fromNow of non-string +context: {} +template: {$fromNow: 13} +error: 'TemplateError: $fromNow expects a string' +--- +title: $fromNow with eval +context: {ttl: 24} +template: {$fromNow: {$eval: 'str(ttl) + " hours"'}} +result: '2017-01-20T16:27:20.974Z' +--- +title: $fromNow with redefined `now` +context: {} +template: {$let: {now: '2019-01-01T01:00:00.123Z'}, in: {$fromNow: '3 mo'}} +result: '2019-04-01T01:00:00.123Z' +--- +title: $fromNow with reference +context: {when: '2019-01-01T01:00:00.123Z'} +template: {$fromNow: '3 mo', from: {$eval: when}} +result: '2019-04-01T01:00:00.123Z' +--- +title: $fromNow with undefined properties +context: {now: '2019-01-01T01:00:00.123Z'} +template: {$fromNow: '3 mo', from: {$eval: now}, foo: 'bar'} +error: 'TemplateError: $fromNow has undefined properties: foo' +################################################################################ +--- +section: $json +--- +title: wrap expressions with $eval +context: {a: 1, b: 2} +template: {$json: {$eval: 'a + b + 7'}} +result: '10' +--- +title: unwrap expressions not evaluated +context: {a: 1, b: 2} +template: {$json: 'a + b + 7'} +result: '"a + b + 7"' +--- +title: $eval inside array +context: {a: 1, b: 2} +template: {$json: [2, 5, {$eval: 'a + b + 7'}]} +result: '[2,5,10]' +--- +title: representation of various unicode codepoints are consistent +context: {} +template: {$json: ["\x10", "Z", "\u0103","\U0001F809"]} +result: "[\"\\u0010\",\"Z\",\"\u0103\",\"\U0001F809\"]" +--- +title: sorting pairs by unicode key strings sorts lexically by codepoint +context: {} +template: {$json: {"\u3347\u0050": 1, "\uE1FF\u0100": 2, "\u0055\u0045": 3}} +result: "{\"\u0055\u0045\":3,\"\u3347\u0050\":1,\"\uE1FF\u0100\":2}" +--- +title: sorting pairs by unicode key strings sorts lexically by codepoint, even with chars above base plane +context: {} +template: {$json: {"\U0001F809\u732b":'hey', "Z\U00010000P": 1, "\U000E1FFF\u0103": 2, "UaE": 3}} +result: "{\"UaE\":3,\"Z\U00010000P\":1,\"\U0001F809\u732b\":\"hey\",\"\U000E1FFF\u0103\":2}" +--- +title: $json with undefined properties +context: {} +template: {$json: [1,2,true,{},[]], foo: 'bar'} +error: 'TemplateError: $json has undefined properties: foo' +--- +title: $json can be evaluated to null without an error +context: {input: null} +template: {$json: { '$eval': 'input' } } +result: 'null' +################################################################################ +--- +section: accessing nested objects => context +--- +title: $eval +context: {key: {key2: ['value', 1, 2, true, {}]}} +template: {$eval: 'key.key2'} +result: ['value', 1, 2, true, {}] +--- +title: $json +context: {key: {key2: [1,2,true,{},[]]}} +template: {$json: {$eval: 'key.key2'}} +result: '[1,2,true,{},[]]' +################################################################################ +--- +section: string interpolation +--- +title: string interpolation +context: {key: {key2: 'world', key3: 1}} +template: {message: 'hello ${key.key2}', 'k-${key.key3}': true} +result: {message: 'hello world', 'k-1': true} +--- +title: string interpolation, first character +context: {somevalue: 13} +template: {message: '${somevalue}'} +result: {message: '13'} +--- +title: no string interpolation with $$ +context: {somevalue: 13} +template: {message: '$${somevalue}'} +result: {message: '${somevalue}'} +################################################################################ +--- +section: $let +--- +title: simple let +template: {$let: {ts: 100, foo: 200,}, in: [{$eval: "ts+foo"}, {$eval: "ts-foo"}, {$eval: "ts*foo"}]} +context: {} +result: [300, -100, 20000] +--- +title: let with evaluated values +template: {$let: {thirty: {$eval: "10 + 20"}}, in: {$eval: "thirty+5"}} +context: {} +result: 35 +--- +title: let with evaluated context +template: {$let: {$eval: '{"thirty": 10 + 20}'}, in: {$eval: "thirty+5"}} +context: {} +result: 35 +--- +title: context overriding +template: {$let: {x: 20}, in: {$eval: "x + y"}} +context: {x: 10, 'y': 1} +result: 21 +--- +title: nested let +template: {$let: {x: 20,'y': 10}, in: {$let: {x: 30}, in: {$eval: "x + y + z"}}} +context: {x: 1,'y': 2, z: 3} +result: 43 +--- +title: let with undefined properties +template: {$let: {x: 1,'y': 2}, a: {$eval: "x + y"}} +context: {} +error: 'TemplateError: $let has undefined properties: a' +--- +title: let array +template: {$let: [1, 2], in: {$eval: "1 + 2"}} +context: {} +error: 'TemplateError: $let value must be an object' +--- +title: let null +template: {$let: null, in: {$eval: "1 + 2"}} +context: {} +error: 'TemplateError: $let value must be an object' +--- +title: checking name begin with number +context: {} +template: {$let: {ab: 100, bb: 200, 2b: 5}, in: [{$eval: "ab+bb"}, {$eval: "ab-bb"}, {$eval: "ab*bb"}]} +error: 'TemplateError: top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/' +--- +title: checking space in variable name +context: {} +template: {$let: {ab: 100, bb: 200, "a b": 10}, in: [{$eval: "ab+bb"}, {$eval: "ab-bb"}, {$eval: "ab*bb"}]} +error: 'TemplateError: top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/' +--- +title: checking special character in variable name +context: {} +template: {$let: {ab: 100, bb: 200, "a.b": 10}, in: [{$eval: "ab+bb"}, {$eval: "ab-bb"}, {$eval: "ab*bb"}]} +error: 'TemplateError: top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/' +--- +title: checking integrity of operation $let with exact result +context: {} +template: {$let: {ts: 100, foo: 200}, in: [{$eval: "ts+foo"}, {$eval: "ts-foo"}, {$eval: "ts*foo"}]} +result: [300, -100, 20000] +--- +title: checking $let and $reverse operator integrity +context: {} +template: {$let: {x: [1, 2, 3]}, in: [$reverse: {$eval: "x"}]} +result: [[ 3, 2, 1 ]] +--- +title: checking $let with $if without else +context: {c: 'itm'} +template: {$let: {a: {$if: 'c == "item"', then: 'value'}}, in: {a: '${a}'}} +error: 'InterpreterError at template.a: unknown context value a' +--- +title: let with a value of $if-then-else +template: {$let: {$if: something == 3, then: {a: 10, b: 20}, else: {a: 20, b: 10}}, in: {$eval: 'a + b'}} +context: {'something': 3} +result: 30 +--- +title: let with a rendered key +template: {$let: {"first_${name}": 1, "second_${name}": 2}, in: {$eval: "first_prize + second_prize"}} +context: {name: "prize"} +result: 3 +--- +title: let using values from the parent context +template: {$let: {"b": {$eval: "a + 10"}}, in: {$eval: "a + b"}} +context: {a: 5} +result: 20 +--- +title: let with a non-object rendered value (array) +template: {$let: {$eval: "[1, 2]"}, in: "uhoh"} +context: {} +error: 'TemplateError: $let value must be an object' +--- +title: let with a non-object rendered value (string) +template: {$let: "${name}", in: "uhoh"} +context: {name: "fido"} +error: 'TemplateError: $let value must be an object' +--- +title: let with a non-object rendered value (boolean) +template: {$let: {$eval: "true"}, in: "uhoh"} +context: {} +error: 'TemplateError: $let value must be an object' +--- +title: fromNow with redefined `now` +context: {} +template: {$let: {now: '2017-01-01T01:00:00.123Z'}, in: {$eval: "fromNow('1 day')"}} +result: '2017-01-02T01:00:00.123Z' +--- +title: defined with empty variable from a let expression +context: {} +template: {$let: {var: 10}, in: {$if: "defined('var')", then: 't', else: 'f'}} +result: t +--- +title: $let with nested redefinitions of builtins +context: {} +template: + $let: {lowercase: {$eval: uppercase}} + in: + $let: {var: 10} + in: + $if: "defined('var')" + then: "${lowercase('t')}" # lowercase should be redefined as uppercase + else: "${lowercase('f')}" +result: T +--- +title: $let with nested redefinitions of builtins +context: {} +template: + $let: {fromNow: {$eval: uppercase}} + in: + $let: {var: 10} + in: + $if: "defined('var')" + then: "${fromNow('1 hour')}" + else: "f" +result: '1 HOUR' +################################################################################ +--- +section: $map +--- +title: simple map +context: {a: 1} +template: + $map: [2, 4, 6] + each(x): {$eval: 'x + a'} +result: [3, 5, 7] +--- +title: map to objects +context: {a: 1} +template: + $map: [2, 4, 6] + each(x): + asText: '${x + a}' + integer: {$eval: 'x + a'} +result: + - {asText: '3', integer: 3} + - {asText: '5', integer: 5} + - {asText: '7', integer: 7} +--- +title: complex identifier +context: {a: 1} +template: + $map: [2, 4, 6] + each(my_identifier97): {$eval: 'my_identifier97 + a'} +result: [3, 5, 7] +--- +title: must wrap expressions with $eval +context: {a: 1} +template: + $map: [2, 4, 6] + each(my_identifier97): 'my_identifier97 + a' +result: ['my_identifier97 + a', 'my_identifier97 + a', 'my_identifier97 + a'] +--- +title: can take from objects +context: {a: 1} +template: + $map: [{k: 1}, {k: 2}, {k: 3}] + each(y): {$eval: 'y.k'} +result: [1, 2, 3] +--- +title: value is rendered +context: {a: 1} +template: + $map: {$eval: '[{k: 1}, {k: 2}, {k: 3}]'} + each(y): {$eval: 'y.k'} +result: [1, 2, 3] +--- +title: can make objects too +context: {a: 1} +template: + $map: [{k: 1}, {k: 2}, {k: 3}] + each(y): + k: {$eval: 'y.k + 1'} + v: 'before=${y.k}' +result: + - k: 2 + v: 'before=1' + - k: 3 + v: 'before=2' + - k: 4 + v: 'before=3' +--- +title: respects delete-marker from $if +context: {a: 1} +template: + $map: [{k: 1}, {k: 2}, {k: 3}] + each(y): + $if: 'y.k != 2' + then: {$eval: 'y.k'} +result: [1, 3] +--- +title: $map works on object +context: {} +template: + $map: {a: 1, b: 2, c: 3} + each(y): {'${y.key}x': {$eval: 'y.val + 1'}} +result: {ax: 2, bx: 3, cx: 4} +--- +title: $map each(value,key) on object +context: {} +template: + $map: {a: 1, b: 2, c: 3} + each(v,k): {'${k}x': {$eval: 'v + 1'}} +result: {ax: 2, bx: 3, cx: 4} +--- +title: $map can add new keys to object +context: {} +template: + $map: {a: 1, b: 2, c: 3} + each(y): {'${y.key}': {$eval: 'y.val'}, '${y.key}x': {$eval: 'y.val + 1'}} +result: {a: 1, b: 2, c: 3, ax: 2, bx: 3, cx: 4} +--- +title: $map array index variable +context: {} +template: + $map: ['a', 'b', 'c'] + each(y,i): '${y}-${i}' +result: ['a-0','b-1','c-2'] +--- +title: $map no args +context: {} +template: + $map: "a, b, c" + each(): {$eval: 'y.k'} +error: 'TemplateError: $map has undefined properties: each()' +--- +title: $map too many args +context: {} +template: + $map: "a, b, c" + each(k,v,i): {$eval: 'y.k'} +error: 'TemplateError: $map has undefined properties: each(k,v,i)' +--- +title: $map requires an array, not string +context: {} +template: + $map: "a, b, c" + each(y): {$eval: 'y.k'} +error: 'TemplateError: $map value must evaluate to an array or object' +--- +title: $map requires an array, not number +context: {} +template: + $map: 10.1 + each(y): {$eval: 'y.k'} +error: 'TemplateError: $map value must evaluate to an array or object' +--- +title: $map requires an array, not null +context: {} +template: + $map: null + each(y): {$eval: 'y.k'} +error: 'TemplateError: $map value must evaluate to an array or object' +--- +title: map with undefined properties +context: {a: 1} +template: + $map: [2, 4, 6] + each(x): {$eval: 'x + a'} + foo: 'bar' +error: 'TemplateError: $map has undefined properties: foo' +--- +title: $map as object and each(identifier) as array +context: {} +template: + $map: {"hello": 5, "test": 9} + each(x): ['${x.key}', {$eval: 'x.val+1'}] +error: 'TemplateError: $map on objects expects each(x) to evaluate to an object' +################################################################################ +--- +section: $match operator +--- +title: $match, 2 matches, ordered by lexcial sorting of property names +context: {cond: 3} +template: {$match: {'cond == 3': 2, 'cond == 5': 3, 'cond < 5 && cond > 0': 4, 'true': 17}} +result: [4, 2, 17] +--- +title: $match, no matches +context: {cond: 3} +template: {$match: {'cond > 5': 2, 'cond == 5': 3, 'cond == 4 || cond < 1': 4}} +result: [] +--- +title: $match, 1 match in array +context: {cond: 3} +template: [0, $match: {'cond == 3': 2, 'cond == 5': 3}] +result: [0, [2]] +--- +title: $match, 0 matches in array +context: {cond: 3} +template: [0, $match: {'cond > 3': 2, 'cond == 5': 3}] +result: [0, []] +--- +title: $match, 1 match in object +context: {cond: 3} +template: {key: 0, banana: {$match: {'cond == 3': 2, 'cond == 5': 3}}} +result: {key: 0, banana: [2]} +--- +title: $match, 0 matches in object +context: {cond: 3} +template: {key: 0, banana: {$match: {'cond > 3': 2, 'cond == 5': 3}}} +result: {key: 0, banana: []} +--- +title: $match, is not an object +context: {cond: 3} +template: {$match: [{'cond < 5 && cond > 0': 2}]} +error: 'TemplateError: $match can evaluate objects only' +--- +title: $match, value that also needs evaluation +context: {cond: 3, ifcond: false} +template: {$match: {'cond == 3': {$if: 'ifcond', then: "t", else: "f"}}} +result: ["f"] +################################################################################ +--- +section: $switch operator +--- +title: $switch, 1 match +context: {cond: 3} +template: {$switch: {'cond == 3': 2, 'cond == 5': 3}} +result: 2 +--- +title: $switch, 2 matches +context: {cond: 3} +template: {$switch: {'cond == 3': 2, 'cond > 1': 3}} +error: 'TemplateError: $switch can only have one truthy condition' +--- +title: $switch, no matches +context: {cond: 3} +template: {$switch: {'cond > 5': 2, 'cond == 5': 3, 'cond == 4 || cond < 1': 4}} +result: null +--- +title: $switch, 1 match in array +context: {cond: 3} +template: [0, $switch: {'cond == 3': 2, 'cond == 5': 3}] +result: [0, 2] +--- +title: $switch, 0 matches in array +context: {cond: 3} +template: [0, $switch: {'cond > 3': 2, 'cond == 5': 3}] +result: [0] +--- +title: $switch, 1 match in object +context: {cond: 3} +template: {key: 0, banana: {$switch: {'cond == 3': 2, 'cond == 5': 3}}} +result: {key: 0, banana: 2} +--- +title: $switch, 0 matches in object +context: {cond: 3} +template: {key: 0, banana: {$switch: {'cond > 3': 2, 'cond == 5': 3}}} +result: {key: 0} +--- +title: $switch, is not an object +context: {cond: 3} +template: {$switch: [{'cond < 5 && cond > 0': 2}]} +error: 'TemplateError: $switch can evaluate objects only' +--- +title: $switch, value that also needs evaluation +context: {cond: 3, ifcond: false} +template: {$switch: {'cond == 3': {$if: 'ifcond', then: "t", else: "f"}}} +result: "f" +--- +title: $switch, fallback to $default +context: {cond: 4} +template: {$switch: {'cond == 3': 1, $default: 'fallback'}} +result: "fallback" +--- +title: $switch, $default value that also needs evaluation +context: {cond: 4, ifcond: false} +template: {$switch: {'cond == 3': 1, $default: {$if: 'ifcond', then: "t", else: "f"}}} +result: "f" +--- +title: $switch, $default with 1 match in object +context: {cond: 3} +template: {$switch: {'cond == 3': 1, $default: 'fallback'}} +result: 1 +############################################################################### +--- +section: $merge +--- +title: simple merge +context: {} +template: {$merge: [{a: 1, b: 1}, {b: 2, c: 3}, {d: 4}]} +result: {a: 1, b: 2, c: 3, d: 4} +--- +title: value is evaluated +context: {defaults: {d: 4}} +template: {$merge: [{a: 1, b: 1}, {b: 2, c: 3}, {$eval: defaults}]} +result: {a: 1, b: 2, c: 3, d: 4} +--- +title: merge empty array +context: {} +template: {$merge: []} +result: {} +--- +title: merge empty array with empty object +context: {} +template: {$merge: [{}]} +result: {} +--- +title: merge null +context: {} +template: {$merge: null} +error: 'TemplateError: $merge value must evaluate to an array of objects' +--- +title: $merge [null] +template: {$merge: [null]} +context: {} +error: 'TemplateError: $merge value must evaluate to an array of objects' +--- +title: merge with undefined properties +template: {$merge: [{a: 1}, {b: 2, c: 3}, {d: 4}], foo: "bar", bing: "baz"} +context: {} +error: 'TemplateError: $merge has undefined properties: bing foo' +################################################################################ +--- +section: $mergeDeep +--- +title: simple non-deep mergeDeep matches merge +context: {} +template: {$mergeDeep: [{a: 1, b: 1}, {b: 2, c: 3}, {d: 4}]} +result: {a: 1, b: 2, c: 3, d: 4} +--- +title: deep merge of lists appends +context: {} +template: {$mergeDeep: [{a: [1, 2]}, {a: [3, 4]}]} +result: {a: [1, 2, 3, 4]} +--- +title: deep merge of objects merges +context: {} +template: {$mergeDeep: [{a: {x: 1,'y': 2}}, {a: {'y': 3, z: 4}}]} +result: {a: {x: 1,'y': 3, z: 4}} +--- +title: very deep merge +context: {} +template: + $mergeDeep: + - task: + payload: + command: [a, b] + - task: + extra: + foo: bar + - task: + payload: + command: [c] +result: + task: + extra: + foo: bar + payload: + command: [a, b, c] +--- +title: value is evaluated +context: {defaults: {d: 4}} +template: {$mergeDeep: [{a: 1, b: 1}, {b: 2, c: 3}, {$eval: defaults}]} +result: {a: 1, b: 2, c: 3, d: 4} +--- +title: mergeDeep empty array +context: {} +template: {$mergeDeep: []} +result: {} +--- +title: mergeDeep empty array with empty object +context: {} +template: {$mergeDeep: [{}]} +result: {} +--- +title: mergeDeep null +context: {} +template: {$mergeDeep: null} +error: 'TemplateError: $mergeDeep value must evaluate to an array of objects' +--- +title: $mergeDeep [null] +template: {$mergeDeep: [null]} +context: {} +error: 'TemplateError: $mergeDeep value must evaluate to an array of objects' +--- +title: mergeDeep with undefined properties +template: {$mergeDeep: [{a: {x: 1,'y': 2}}, {a: {'y': 3, z: 4}}], foo: "bar", bing: "baz"} +context: {} +error: 'TemplateError: $mergeDeep has undefined properties: bing foo' +################################################################################ +--- +section: $sort +--- +title: simple sort +context: {} +template: {$sort: [3, 4, 1, 2]} +result: [1, 2, 3, 4] +--- +title: simple sort of strings (shortest first) +context: {} +template: {$sort: ['android', 'aardvark', 'add', 'adderall']} +result: ['aardvark', 'add', 'adderall', 'android'] +--- +title: simple sort of multi-digit numbers +context: {} +template: {$sort: [111, 22, 3]} +result: [3, 22, 111] +--- +title: sort of mixed array +context: {} +template: {$sort: [1, "2", 2, 3, "111", "112"]} +error: true +--- +title: simple sort with $eval +context: {array: [3, 4, 1, 2]} +template: {$sort: {$eval: 'array'}} +result: [1, 2, 3, 4] +--- +title: sort by, returning number +context: {} +template: + $sort: [{a: 20}, {a: 10, b: []}, {a: 3}] + by(x): 'x.a' +result: [{a: 3}, {a: 10, b: []}, {a: 20}] +--- +title: sort by, returning string +context: {} +template: + $sort: [{s: 'android'}, {s: 'add'}, {s: 'adderall'}] + by(x): 'x.s' +result: [{s: 'add'}, {s: 'adderall'}, {s: 'android'}] +--- +title: cannot sort objects without by +context: {} +template: + $sort: [{a: 2}, {a: 1, b: []}, {a: 3}] +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: by cannot return objects +context: {} +template: + $sort: [{a: 2}, {a: 1, b: []}, {a: 3}] + by(x): x +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort arrays without by +context: {} +template: + $sort: [[1,2,3], [4,5], [], [8,9,10]] +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: by cannot return arrays +context: {} +template: + $sort: [[1,2,3], [4,5], [], [8,9,10]] + by(x): x +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort nulls +context: {} +template: {$sort: [null, null]} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort nulls, even with by +context: {} +template: {$sort: [null, null], 'by(x)': 'x'} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort booleans +context: {} +template: {$sort: [false, true]} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort booleans, even with by +context: {} +template: {$sort: [false, true], 'by(x)': 'x'} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort numbers and strings together +context: {} +template: {$sort: [1, 'a']} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: cannot sort numbers and strings together even with by +context: {} +template: {$sort: [1, 'a'], 'by(x)': 'x'} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: sort requires an array (string) +context: {} +template: + $sort: "some string" +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: sort requires an array (number) +context: {} +template: + $sort: 34 +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: sort requires an array (object) +context: {} +template: + $sort: {k: 1, b: 4, x: 8} +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: sort requires an array (null) +context: {} +template: + $sort: null +error: 'TemplateError: $sorted values to be sorted must have the same type' +--- +title: sort with undefined properties +context: {} +template: + $sort: [{s: 'android'}, {s: 'add'}, {s: 'adderall'}] + by(x): 'x.s' + foo: 'bar' +error: 'TemplateError: $sort has undefined properties: foo' + +################################################################################ +--- +section: $reverse +--- +title: simple reverse +context: {} +template: {$reverse: [3, 4, 1, 2]} +result: [2, 1, 4, 3] +--- +title: value is rendered +context: {} +template: {$reverse: {$eval: '[99, 999, 9]'}} +result: [9, 999, 99] +--- +title: reverse of an object +context: {} +template: {$reverse: {a: 1}} +error: 'TemplateError: $reverse value must evaluate to an array of objects' +--- +title: reverse of null +context: {} +template: {$reverse: null} +error: 'TemplateError: $reverse value must evaluate to an array of objects' +--- +title: reverse of a string +context: {} +template: {$reverse: 'foo'} +error: 'TemplateError: $reverse value must evaluate to an array of objects' +--- +title: reverse of a number +context: {} +template: {$reverse: 1} +error: 'TemplateError: $reverse value must evaluate to an array of objects' +--- +title: reverse of a boolean +context: {} +template: {$reverse: true} +error: 'TemplateError: $reverse value must evaluate to an array of objects' +--- +title: simple reverse with $eval +context: {key: [3, 4, 1, 2]} +template: {$reverse: {$eval: 'key'}} +result: [2, 1, 4, 3] +--- +title: simple reverse + $sort # with this we can sort in reverse order +context: {} +template: {$reverse: {$sort: [3, 4, 1, 2]}} +result: [4, 3, 2, 1] +--- +title: reverse with undefined properties +template: {$reverse: [3, 4, 1, 2], foo: "bar", bing: "baz"} +context: {} +error: 'TemplateError: $reverse has undefined properties: bing foo' +################################################################################ +--- +section: $eval +--- +title: $eval of $eval +context: {} +template: {$eval: {$eval: '"13"'}} +error: 'TemplateError: $eval must be given a string expression' +--- +title: $eval with undefined properties +context: {} +template: {$eval: '13', wrong: 'a + b'} +error: 'TemplateError: $eval has undefined properties: wrong' +--- +title: $eval of an array +context: {key1: 1, key2: 2} +template: {$eval: ['key1', 'key2']} +error: 'TemplateError: $eval must be given a string expression' +--- +title: $eval of an object +context: {key1: 1, key2: 2} +template: {$eval: {k: 'key1'}} +error: 'TemplateError: $eval must be given a string expression' +--- +title: $eval of null +context: {} +template: {$eval: null} +error: 'TemplateError: $eval must be given a string expression' +--- +title: $eval of a number +context: {} +template: {$eval: 11} +error: 'TemplateError: $eval must be given a string expression' +--- +title: $eval of a boolean +context: {} +template: {$eval: true} +error: 'TemplateError: $eval must be given a string expression' +################################################################################ +--- +section: builtins +--- +title: min (1) +context: {key1: 1, key2: 2} +template: {$eval: 'min(key1, key2)'} +result: 1 +--- +title: min (2) +context: {key1: 1, key2: 2} +template: {$eval: 'min(1, key2)'} +result: 1 +--- +title: min (3) +context: {key1: 1, key2: 2} +template: {$eval: 'min(key1, 2)'} +result: 1 +--- +title: min (4) +context: {key1: 1, key2: 2} +template: {$eval: 'min(1, 2)'} +result: 1 +--- +title: min (5) +context: {key1: 1, key2: 2} +template: {$eval: 'min(2, 1)'} +result: 1 +--- +title: min (6) +context: {key1: 1, key2: 2} +template: {$eval: 'min(2, 1, 3, 4, 5)'} +result: 1 +--- +title: min - TypeError +context: {} +template: {$eval: 'min("11")'} +error: 'BuiltinError: invalid arguments to builtin: min' +--- +title: min (7) +context: {} +template: {$eval: 'min()'} +error: 'BuiltinError: invalid arguments to builtin: min: expected at least 1 arguments' +--- +title: max (1) +context: {key1: 1, key2: 2} +template: {$eval: 'max(key1, key2)'} +result: 2 +--- +title: max (2) +context: {key1: 1, key2: 2} +template: {$eval: 'max(1, key2)'} +result: 2 +--- +title: max (3) +context: {key1: 1, key2: 2} +template: {$eval: 'max(key1, 2)'} +result: 2 +--- +title: max (4) +context: {key1: 1, key2: 2} +template: {$eval: 'max(1, 2)'} +result: 2 +--- +title: max (5) +context: {key1: 1, key2: 2} +template: {$eval: 'max(2, 1)'} +result: 2 +--- +title: max (6) +context: {key1: 1, key2: 2} +template: {$eval: 'max(2, 1, 3, 4, 5)'} +result: 5 +--- +title: max - TypeError +context: {} +template: {$eval: 'max("12")'} +error: 'BuiltinError: invalid arguments to builtin: max' +--- +title: max (7) +context: {} +template: {$eval: 'max()'} +error: 'BuiltinError: invalid arguments to builtin: max: expected at least 1 arguments' +--- +title: sqrt (1) +context: {key: 4} +template: {$eval: 'sqrt(key)'} +result: 2 +--- +title: sqrt (2) +context: {} +template: {$eval: 'sqrt(9)'} +result: 3 +--- +title: sqrt - TypeError +context: {} +template: {$eval: 'sqrt("nine")'} +error: 'BuiltinError: invalid arguments to builtin: sqrt' +--- +title: ceil (1) +context: {key: 1.1} +template: {$eval: 'ceil(key)'} +result: 2 +--- +title: ceil (2) +context: {} +template: {$eval: 'ceil(2.003)'} +result: 3 +--- +title: ceil (3) +context: {key: 1} +template: {$eval: 'ceil(key)'} +result: 1 +--- +title: ceil (4) +context: {key: 1.0} +template: {$eval: 'ceil(key)'} +result: 1 +--- +title: ceil - TypeError +context: {} +template: {$eval: 'ceil(true)'} +error: 'BuiltinError: invalid arguments to builtin: ceil' +--- +title: floor (1) +context: {key: 1.1} +template: {$eval: 'floor(key)'} +result: 1 +--- +title: floor (2) +context: {} +template: {$eval: 'floor(2.003)'} +result: 2 +--- +title: floor (3) +context: {key: 1} +template: {$eval: 'floor(key)'} +result: 1 +--- +title: floor (4) +context: {key: 1.0} +template: {$eval: 'floor(key)'} +result: 1 +--- +title: floor - TypeError +context: {key: null} +template: {$eval: 'floor(key)'} +error: 'BuiltinError: invalid arguments to builtin: floor' +--- +title: abs (1) +context: {key: -1.1} +template: {$eval: 'abs(key)'} +result: 1.1 +--- +title: abs (2) +context: {} +template: {$eval: 'abs(-1.1)'} +result: 1.1 +--- +title: abs (3) +context: {key: -1} +template: {$eval: 'abs(key)'} +result: 1 +--- +title: abs (4) +context: {key: -1.0} +template: {$eval: 'abs(key)'} +result: 1 +--- +title: abs (5) +context: {} +template: {$eval: 'abs(-1)'} +result: 1 +--- +title: abs (6) +context: {} +template: {$eval: 'abs(-1.0)'} +result: 1 +--- +title: abs (7) +context: {key: 1.1} +template: {$eval: 'abs(key)'} +result: 1.1 +--- +title: abs (8) +context: {} +template: {$eval: 'abs(1.1)'} +result: 1.1 +--- +title: abs (9) +context: {key: 1} +template: {$eval: 'abs(key)'} +result: 1 +--- +title: abs (10) +context: {key: 1.0} +template: {$eval: 'abs(key)'} +result: 1 +--- +title: abs (11) +context: {} +template: {$eval: 'abs(1)'} +result: 1 +--- +title: abs (12) +context: {} +template: {$eval: 'abs(1.0)'} +result: 1 +--- +title: abs - TypeError +context: {} +template: {$eval: 'abs({})'} +error: 'BuiltinError: invalid arguments to builtin: abs' +--- +title: lowercase (1) +context: {key: 'HEllo'} +template: {$eval: 'lowercase(key)'} +result: 'hello' +--- +title: lowercase (2) +context: {} +template: {$eval: 'lowercase("HEllo")'} +result: 'hello' +--- +title: TypeError lowercase (1) +context: {key: {}} +template: {$eval: 'lowercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: TypeError lowercase (2) +context: {} +template: {$eval: 'lowercase({})'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: TypeError lowercase (3) +context: {key: []} +template: {$eval: 'lowercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: TypeError lowercase (4) +context: {} +template: {$eval: 'lowercase([])'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: TypeError lowercase (5) +context: {key: 1} +template: {$eval: 'lowercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: TypeError lowercase (6) +context: {} +template: {$eval: 'lowercase(1)'} +error: 'BuiltinError: invalid arguments to builtin: lowercase' +--- +title: uppercase (1) +context: {key: 'HEllo'} +template: {$eval: 'uppercase(key)'} +result: 'HELLO' +--- +title: uppercase (2) +context: {} +template: {$eval: 'uppercase("HEllo")'} +result: 'HELLO' +--- +title: TypeError uppercase (1) +context: {key: {}} +template: {$eval: 'uppercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: TypeError uppercase (2) +context: {} +template: {$eval: 'uppercase({})'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: TypeError uppercase (3) +context: {key: []} +template: {$eval: 'uppercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: TypeError uppercase (4) +context: {} +template: {$eval: 'uppercase([])'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: TypeError uppercase (5) +context: {key: 1} +template: {$eval: 'uppercase(key)'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: TypeError uppercase (6) +context: {} +template: {$eval: 'uppercase(1)'} +error: 'BuiltinError: invalid arguments to builtin: uppercase' +--- +title: len (1) +context: {key: [1,2,3]} +template: {$eval: 'len(key)'} +result: 3 +--- +title: len (2) +context: {key: [1,2,3]} +template: {$eval: 'len([1, 2, 3])'} +result: 3 +--- +title: len (3) +context: {key: 'abc'} +template: {$eval: 'len(key)'} +result: 3 +--- +title: len of grinning face unicode character +context: {key: "\U0001F601"} +template: {$eval: 'len(key)'} +result: 1 +--- +title: len (4) +context: {key: [1,2,3]} +template: {$eval: 'len("abc")'} +result: 3 +--- +title: TypeError len (1) +context: {key: {}} +template: {$eval: 'len(key)'} +error: 'BuiltinError: invalid arguments to builtin: len' +--- +title: TypeError len (2) +context: {} +template: {$eval: 'len({})'} +error: 'BuiltinError: invalid arguments to builtin: len' +--- +title: TypeError len (3) +context: {key: 1} +template: {$eval: 'len(key)'} +error: 'BuiltinError: invalid arguments to builtin: len' +--- +title: TypeError len (4) +context: {} +template: {$eval: 'len(1)'} +error: 'BuiltinError: invalid arguments to builtin: len' +--- +title: str (1) +context: {key: 1} +template: {$eval: 'str(key)'} +result: '1' +--- +title: str (2) +context: {} +template: {$eval: 'str(1)'} +result: '1' +--- +title: str (3) +context: {key: 'hello'} +template: {$eval: 'str(key)'} +result: 'hello' +--- +title: str (4) +context: {} +template: {$eval: 'str("hello")'} +result: 'hello' +--- +title: str (3) +context: {key: 'hello'} +template: {$eval: 'str(key)'} +result: 'hello' +--- +title: str (4) +context: {} +template: {$eval: 'str("hello")'} +result: 'hello' +--- +title: str (5) +context: {key: true} +template: {$eval: 'str(key)'} +result: 'true' +--- +title: str (6) +context: {} +template: {$eval: 'str(true)'} +result: 'true' +--- +title: str (key) with null +context: {x: null} +template: {$eval: 'str(x)'} +result: 'null' +--- +title: str (7) +context: {key: false} +template: {$eval: 'str(key)'} +result: 'false' +--- +title: str (8) +context: {} +template: {$eval: 'str(false)'} +result: 'false' +--- +title: str (9) +context: {val: 24} +template: {$eval: 'str(val)'} +result: '24' +--- +title: str (unicode) +context: {val: "let's make a ☃"} +template: {$eval: 'str(val)'} +result: "let's make a ☃" +--- +title: str({}) +context: {} +template: {$eval: 'str({})'} +error: 'BuiltinError: invalid arguments to builtin: str' +--- +title: str({a:10}) +context: {} +template: {$eval: 'str({a:10})'} +error: 'BuiltinError: invalid arguments to builtin: str' +--- +title: str([1, 2, 3]) +context: {} +template: {$eval: 'str([1, 2, 3])'} +error: 'BuiltinError: invalid arguments to builtin: str' +--- +title: str(key) with array +context: {key: [1, 2, 3]} +template: {$eval: 'str(key)'} +error: 'BuiltinError: invalid arguments to builtin: str' +--- +title: number +context: {round: "3"} +template: {foo: {$eval: number(round)}} +result: {foo: 3} +--- +title: number (with point) +context: {round: "3.5"} +template: {foo: {$eval: number(round)}} +result: {foo: 3.5} +--- +title: negative number +context: {round: "-14"} +template: {foo: {$eval: number(round)}} +result: {foo: -14} +--- +title: negative number (with point) +context: {round: "-14.15"} +template: {foo: {$eval: number(round)}} +result: {foo: -14.15} +--- +title: number zero +context: {round: "0"} +template: {foo: {$eval: number(round)}} +result: {foo: 0} +--- +title: giving a number to number fails +context: {round: 0} +template: {foo: {$eval: number(round)}} +error: true +--- +title: giving a bool to number fails +context: {round: false} +template: {foo: {$eval: number(round)}} +error: true +--- +title: giving null to number fails +context: {round: null} +template: {foo: {$eval: number(round)}} +error: true +--- +title: giving an array to number fails +context: {round: [1]} +template: {foo: {$eval: number(round)}} +error: true +--- +title: giving an object to number fails +context: {round: {one: 1}} +template: {foo: {$eval: number(round)}} +error: true +--- +title: strip space +context: {} +template: {$eval: "strip(' abc ')"} +result: 'abc' +--- +title: strip mixed whitspace +context: {} +template: {$eval: "strip(' \f\n\r\t\vabc \f\n\r\t\v')"} +result: 'abc' +--- +title: rstrip space +context: {} +template: {$eval: "rstrip(' abc ')"} +result: ' abc' +--- +title: rstrip mixed whitspace +context: {} +template: {$eval: "rstrip(' \f\n\r\t\vabc \f\n\r\t\v')"} +result: " \f\n\r\t\vabc" +--- +title: lstrip space +context: {} +template: {$eval: "lstrip(' abc ')"} +result: 'abc ' +--- +title: lstrip mixed whitspace +context: {} +template: {$eval: "lstrip(' \f\n\r\t\vabc \f\n\r\t\v')"} +result: "abc \f\n\r\t\v" +--- +title: split string with delimiter +context: {} +template: {$eval: "split('left:right', ':')"} +result: ['left', 'right'] +--- +title: split string without delimiter +context: {} +template: {$eval: "split('spellme', '')"} +result: ['s', 'p', 'e', 'l', 'l', 'm', 'e'] +--- +title: split with empty string +context: {} +template: {$eval: "split('', ':')"} +result: [''] +--- +title: split string with no match +context: {} +template: {$eval: "split('no semicolon', ':')"} +result: ['no semicolon'] +--- +title: split with number delimiter +context: {} +template: {$eval: "split('left1right', 1)"} +result: ['left', 'right'] +--- +title: split error with object +context: {} +template: {$eval: "split({})"} +error: 'BuiltinError: invalid arguments to builtin: split' +--- +title: split error with array +context: {} +template: {$eval: "split([])"} +error: 'BuiltinError: invalid arguments to builtin: split' +--- +title: join with string separator +context: {} +template: {$eval: "join(['join', 'me'], ' ')"} +result: "join me" +--- +title: join with same +context: {} +template: {$eval: "join([',', ','], ',')"} +result: ",,," +--- +title: join with number separator +context: {} +template: {$eval: "join([1, 3], 2)"} +result: "123" +--- +title: join with strings separated with number +context: {} +template: {$eval: "join(['one', 'three'], 2)"} +result: "one2three" +--- +title: join with numbers separated with string +context: {} +template: {$eval: "join([1, 3], 'two')"} +result: "1two3" +--- +title: join with string +context: {} +template: {$eval: "join('cannot join string')"} +error: "BuiltinError: invalid arguments to builtin: join" +--- +title: join with object +context: {} +template: {$eval: "join({})"} +error: "BuiltinError: invalid arguments to builtin: join" +--- +title: join with boolean +context: {} +template: {$eval: "join(false)"} +error: "BuiltinError: invalid arguments to builtin: join" +--- +title: fromNow +context: {} +template: {$eval: fromNow("")} +result: '2017-01-19T16:27:20.974Z' +--- +title: fromNow - 2 days 3 hours +context: {} +template: {$eval: fromNow("2 days 3 hours")} +result: '2017-01-21T19:27:20.974Z' +--- +title: fromNow with reference +context: {} +template: {$eval: "fromNow('1 day', '2017-01-01T01:00:00.123Z')"} +result: '2017-01-02T01:00:00.123Z' +--- +title: fromNow - TypeError +context: {} +template: {$eval: fromNow(13)} +error: 'BuiltinError: invalid arguments to builtin: fromNow' +--- +title: typeof str +context: {} +template: {$eval: typeof('abc')} +result: string +--- +title: typeof number (int) +context: {} +template: {$eval: typeof(4)} +result: number +--- +title: typeof number (float) +context: {} +template: {$eval: typeof(4.0)} +result: number +--- +title: typeof boolean (true) +context: {} +template: {$eval: typeof(true)} +result: boolean +--- +title: typeof boolean (false) +context: {} +template: {$eval: typeof(false)} +result: boolean +--- +title: typeof array (empty) +context: {} +template: {$eval: 'typeof([])'} +result: array +--- +title: typeof array +context: {} +template: {$eval: 'typeof([1, 2, 3])'} +result: array +--- +title: typeof object +context: {} +template: {$eval: 'typeof({})'} +result: object +--- +title: typeof null +context: {x: null} +template: {$eval: 'typeof(x)'} +result: 'null' +--- +title: typeof null, interpolated +context: {x: null} +template: "${typeof(x)}" +result: 'null' +--- +title: typeof null in if +context: {} +template: {$if: 'typeof(null) == "null"', then: 'foo', else: 'bar'} +result: foo +--- +title: typeof function +context: {} +template: {$eval: 'typeof(typeof)'} +result: function +--- +title: override builtin (1), uppercase +context: {uppercase: 1} +template: {$eval: 'uppercase + 1'} +result: 2 +--- +title: override builtin (2), min +context: {min: 'hello world!'} +template: {$eval: 'min'} +result: 'hello world!' +--- +title: 'defined without context variable' +context: {} +template: {$if: "defined('var')", then: 't', else: 'f'} +result: f +--- +title: 'defined with empty string as context variable' +context: {var: ""} +template: {$if: "defined('var')", then: 't', else: 'f'} +result: t +################################################################################ +--- +section: expression language - basics +--- +title: missing right square bracket +context: {bar: "mystring"} +template: {foo: '${bar[2:}'} +error: "SyntaxError at template.foo: Found: } token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: decimal literal +context: {} +template: {$eval: '10.5'} +result: 10.5 +--- +title: hex literal +context: {} +template: {$eval: '0xff'} +error: 'SyntaxError: Found: xff token, expected one of: !=, &&, (, *, **, +, -, ., /, <, <=, ==, >, >=, [, in, ||' +--- +title: string literal with single quote +context: {} +template: {$eval: "'three!'"} +result: 'three!' +--- +title: string literal with double quote +context: {} +template: {$eval: '"three!"'} +result: 'three!' +--- +title: string literal escape with backslash (not supported) +context: {} +template: {$eval: '"backslash\\"maybe"'} +error: 'SyntaxError: Found: maybe token, expected one of: !=, &&, (, *, **, +, -, ., /, <, <=, ==, >, >=, [, in, ||' +--- +title: string literal escape with doubling (not supported) +context: {} +template: {$eval: '"doubled""maybe"'} +error: 'SyntaxError: Found: "maybe" token, expected one of: !=, &&, (, *, **, +, -, ., /, <, <=, ==, >, >=, [, in, ||' +--- +title: boolean literals +context: {} +template: {$eval: '[true, false]'} +result: [true, false] +--- +title: null literal +context: {} +template: {$eval: '[null, null]'} +result: [null, null] +--- +title: leading zeroes (not octal) +context: {} +template: {$eval: '0777'} +result: 777 +--- +title: addition +context: {a: 1, b: 2} +template: {$eval: 'a + b + 7'} +result: 10 +--- +title: multiplication +context: {a: 3, b: 2} +template: {$eval: 'a * b * 3'} +result: 18 +--- +title: string concatenation +context: {a: 3, b: 2} +template: {$eval: '"a" + "b"'} +result: 'ab' +--- +title: $eval must take string +context: {a: 3, b: 2} +template: {$eval: ['a', 'b']} +error: 'TemplateError: $eval must be given a string expression' +--- +title: array access [index] +context: {a: [1,2,3,4]} +template: {$eval: 'a[0]'} +result: 1 +--- +title: array access [index] +context: {a: [1,2,3,4]} +template: {$eval: 'a[2]'} +result: 3 +--- +title: array access [-index] +context: {a: [1,2,3,4]} +template: {$eval: 'a[-1]'} +result: 4 +--- +title: array access [-index] +context: {a: [1,2,3,4]} +template: {$eval: 'a[-2]'} +result: 3 +--- +title: array slicing [begin:end], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[0:2]'} +result: [1,2] +--- +title: array slicing [begin:], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[0:]'} +result: [1,2,3,4] +--- +title: array slicing [begin:], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[1:]'} +result: [2,3,4] +--- +title: array slicing [-begin:], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[-3:]'} +result: [2,3,4] +--- +title: array slicing [-begin:-end], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[-3:-1]'} +result: [2,3] +--- +title: array slicing [:end], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[:3]'} +result: [1,2,3] +--- +title: array slicing [:-end], [begin, end) +context: {a: [1,2,3,4]} +template: {$eval: 'a[:-2]'} +result: [1,2] +--- +title: array slice partially out of range +context: {a: [1,2,3,4]} +template: {$eval: 'a[2:10]'} +result: [3,4] +--- +title: array slice completely out of range +context: {a: [1,2,3,4]} +template: {$eval: 'a[8:10]'} +result: [] +--- +title: array slice negative out of range +context: {a: [1,2,3,4]} +template: {$eval: 'a[2:-10]'} +result: [] +--- +title: array slice negative range +context: {a: [1,2,3,4]} +template: {$eval: 'a[2:-3]'} +result: [] +--- +title: array slice reverse range +context: {a: [1,2,3,4]} +template: {$eval: 'a[3:2]'} +result: [] +--- +title: function min(contextValue, contextValue) +context: {a: 1, b: 2} +template: {$eval: 'min(a, b)'} +result: 1 +--- +title: function max(contextValue, contextValue) +context: {a: 1, b: 2} +template: {$eval: 'max(a, b)'} +result: 2 +--- +title: function min(contextValue, value) +context: {a: 1, b: 2} +template: {$eval: 'min(a, -1)'} +result: -1 +--- +title: function max(contextValue, value) +context: {a: 1, b: 2} +template: {$eval: 'max(a, 3)'} +result: 3 +--- +title: identifier beginning with in +context: {input: 6} +template: {$eval: 'input + 1'} +result: 7 +--- +title: identifier beginning with true / false +context: {true_facts: true, false_lies: false} +template: {$eval: 'true_facts || false_lies'} +result: true +--- +title: identifier beginning with null +context: {null_hypothesis: "no difference"} +template: {$eval: 'null_hypothesis'} +result: "no difference" +################################################################################ +--- +section: expression language - arithmetic +--- +title: 'addition' +context: {a: 1, b: 2} +template: {$eval: 'a + b + 7'} +result: 10 +--- +title: 'multiplication' +context: {a: 3, b: 2} +template: {$eval: 'a * b * 3'} +result: 18 +--- +title: 'division (1)' +context: {a: 3, b: 2} +template: {$eval: 'a / b'} +result: 1.5 +--- +title: 'division (2)' +context: {a: 3.0, b: 2.0} +template: {$eval: 'a / b'} +result: 1.5 +--- +title: 'division (3)' +context: {a: 3, b: 2} +template: {$eval: 'b / a'} +result: 0.6666666666666666 +--- +title: 'division (4)' +context: {a: 3.0, b: 2.0} +template: {$eval: 'b / a'} +result: 0.6666666666666666 +--- +title: 'exponentiation (1)' +context: {a: 2, b: 3} +template: {$eval: 'a ** b'} +result: 8 +--- +title: 'exponentiation (2)' +context: {a: 2, b: 3} +template: {$eval: 'a ** b + 2'} +result: 10 +--- +title: 'exponentiation (3)' +context: {a: 2, b: 3} +template: {$eval: 'a ** b * 2'} +result: 16 +--- +title: 'exponentiation (4)' +context: {a: 2, b: 3} +template: {$eval: 'a * a ** b'} +result: 16 +--- +title: 'exponentiation, right associativity (1)' +context: {a: 2, b: 3} +template: {$eval: 'a ** a ** b == a ** (a ** b)'} +result: true +--- +title: 'exponentiation, right associativity (2)' +context: {a: 2, b: 3} +template: {$eval: 'a ** a ** b'} +result: 256 +--- +title: 'exponentiation, right associativity (3)' +context: {a: 2, b: 3} +template: {$eval: '2 ** 2 ** 3 == 2 ** (2 ** 3)'} +result: true +--- +title: 'exponentiation, right associativity (4)' +context: {a: 2, b: 3} +template: {$eval: '2 ** 2 ** 3'} +result: 256 +--- +title: 'unary negation' +context: {a: 2} +template: {$eval: '-a'} +result: -2 +--- +title: 'unary plus' +context: {a: 2} +template: {$eval: '+a'} +result: 2 +################################################################################ +--- +section: expression language - operator type errors +--- +title: 'addition of strings to numbers' +context: {a: 'a', b: 1} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of strings to null' +context: {a: 'a', b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of strings to booleans' +context: {a: 'a', b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of strings to objects' +context: {a: 'a', b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of strings to arrays' +context: {a: 'a', b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of strings from strings' +context: {a: 'a', b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of strings from numbers' +context: {a: 'a', b: 1} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of strings from null' +context: {a: 'a', b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of strings from booleans' +context: {a: 'a', b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of strings from objects' +context: {a: 'a', b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of strings from arrays' +context: {a: 'a', b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of strings to strings' +context: {a: 'a', b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of strings to numbers' +context: {a: 'a', b: 1} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of strings to null' +context: {a: 'a', b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of strings to booleans' +context: {a: 'a', b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of strings to objects' +context: {a: 'a', b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of strings to arrays' +context: {a: 'a', b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of strings by strings' +context: {a: 'a', b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of strings by numbers' +context: {a: 'a', b: 1} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of strings by null' +context: {a: 'a', b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of strings by booleans' +context: {a: 'a', b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of strings by objects' +context: {a: 'a', b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of strings by arrays' +context: {a: 'a', b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of strings by strings' +context: {a: 'a', b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of strings by numbers' +context: {a: 'a', b: 1} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of strings by null' +context: {a: 'a', b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of strings by booleans' +context: {a: 'a', b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of strings by objects' +context: {a: 'a', b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of strings by arrays' +context: {a: 'a', b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'unary negation of string' +context: {a: 'a'} +template: {$eval: '-a'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of string' +context: {a: 'a'} +template: {$eval: '+a'} +error: 'InterpreterError: unary + expects number' +--- +title: 'unary negation of true' +template: {$eval: '-true'} +context: {} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of true' +template: {$eval: '+true'} +context: {} +error: 'InterpreterError: unary + expects number' +--- +title: 'unary negation of false' +template: {$eval: '-false'} +context: {} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of false' +template: {$eval: '+false'} +context: {} +error: 'InterpreterError: unary + expects number' +--- +title: 'unary negation of null' +template: {$eval: '-null'} +context: {} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of null' +template: {$eval: '+null'} +context: {} +error: 'InterpreterError: unary + expects number' +--- +title: 'addition of numbers to strings' +context: {a: 13, b: 'b'} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of numbers to null' +context: {a: 13, b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of numbers to booleans' +context: {a: 13, b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of numbers to objects' +context: {a: 13, b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of numbers to arrays' +context: {a: 13, b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of numbers from strings' +context: {a: 13, b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of numbers from null' +context: {a: 13, b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of numbers from booleans' +context: {a: 13, b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of numbers from objects' +context: {a: 13, b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of numbers from arrays' +context: {a: 13, b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of numbers to strings' +context: {a: 13, b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of numbers to null' +context: {a: 13, b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of numbers to booleans' +context: {a: 13, b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of numbers to objects' +context: {a: 13, b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of numbers to arrays' +context: {a: 13, b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of numbers by strings' +context: {a: 13, b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of numbers by null' +context: {a: 13, b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of numbers by booleans' +context: {a: 13, b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of numbers by objects' +context: {a: 13, b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of numbers by arrays' +context: {a: 13, b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of numbers by strings' +context: {a: 13, b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of numbers by null' +context: {a: 13, b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of numbers by booleans' +context: {a: 13, b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of numbers by objects' +context: {a: 13, b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of numbers by arrays' +context: {a: 13, b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'addition of null to strings' +context: {a: null, b: 'a'} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of null to numbers' +context: {a: null, b: 1} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of null to null' +context: {a: null, b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of null to booleans' +context: {a: null, b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of null to objects' +context: {a: null, b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of null to arrays' +context: {a: null, b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of null from strings' +context: {a: null, b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of null from numbers' +context: {a: null, b: 1} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of null from null' +context: {a: null, b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of null from booleans' +context: {a: null, b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of null from objects' +context: {a: null, b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of null from arrays' +context: {a: null, b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of null to strings' +context: {a: null, b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of null to numbers' +context: {a: null, b: 1} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of null to null' +context: {a: null, b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of null to booleans' +context: {a: null, b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of null to objects' +context: {a: null, b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of null to arrays' +context: {a: null, b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of null by strings' +context: {a: null, b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of null by numbers' +context: {a: null, b: 1} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of null by null' +context: {a: null, b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of null by booleans' +context: {a: null, b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of null by objects' +context: {a: null, b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of null by arrays' +context: {a: null, b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of null by strings' +context: {a: null, b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of null by numbers' +context: {a: null, b: 1} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of null by null' +context: {a: null, b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of null by booleans' +context: {a: null, b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of null by objects' +context: {a: null, b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of null by arrays' +context: {a: null, b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'unary negation of null' +context: {a: null} +template: {$eval: '-a'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of null' +context: {a: null} +template: {$eval: '+a'} +error: 'InterpreterError: unary + expects number' +--- +title: 'addition of boolean to strings' +context: {a: true, b: 'a'} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of boolean to numbers' +context: {a: true, b: 1} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of boolean to null' +context: {a: true, b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of boolean to booleans' +context: {a: true, b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of boolean to objects' +context: {a: true, b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of boolean to arrays' +context: {a: true, b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of boolean from strings' +context: {a: true, b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of boolean from numbers' +context: {a: true, b: 1} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of boolean from null' +context: {a: true, b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of boolean from booleans' +context: {a: true, b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of boolean from objects' +context: {a: true, b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of boolean from arrays' +context: {a: true, b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of boolean to strings' +context: {a: true, b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of boolean to numbers' +context: {a: true, b: 1} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of boolean to null' +context: {a: true, b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of boolean to booleans' +context: {a: true, b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of boolean to objects' +context: {a: true, b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of boolean to arrays' +context: {a: true, b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of boolean by strings' +context: {a: true, b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of boolean by numbers' +context: {a: true, b: 1} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of boolean by null' +context: {a: true, b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of boolean by booleans' +context: {a: true, b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of boolean by objects' +context: {a: true, b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of boolean by arrays' +context: {a: true, b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of boolean by strings' +context: {a: true, b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of boolean by numbers' +context: {a: true, b: 1} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of boolean by null' +context: {a: true, b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of boolean by booleans' +context: {a: true, b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of boolean by objects' +context: {a: true, b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of boolean by arrays' +context: {a: true, b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'unary negation of boolean' +context: {a: true} +template: {$eval: '-a'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of boolean' +context: {a: true} +template: {$eval: '+a'} +error: 'InterpreterError: unary + expects number' +--- +title: 'addition of object to strings' +context: {a: {x: 10}, b: 'a'} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of object to numbers' +context: {a: {x: 10}, b: 1} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of object to null' +context: {a: {x: 10}, b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of object to booleans' +context: {a: {x: 10}, b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of object to objects' +context: {a: {x: 10}, b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of object to arrays' +context: {a: {x: 10}, b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of object from strings' +context: {a: {x: 10}, b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of object from numbers' +context: {a: {x: 10}, b: 1} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of object from null' +context: {a: {x: 10}, b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of object from booleans' +context: {a: {x: 10}, b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of object from objects' +context: {a: {x: 10}, b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of object from arrays' +context: {a: {x: 10}, b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of object to strings' +context: {a: {x: 10}, b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of object to numbers' +context: {a: {x: 10}, b: 1} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of object to null' +context: {a: {x: 10}, b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of object to booleans' +context: {a: {x: 10}, b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of object to objects' +context: {a: {x: 10}, b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of object to arrays' +context: {a: {x: 10}, b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of object by strings' +context: {a: {x: 10}, b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of object by numbers' +context: {a: {x: 10}, b: 1} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of object by null' +context: {a: {x: 10}, b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of object by booleans' +context: {a: {x: 10}, b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of object by objects' +context: {a: {x: 10}, b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of object by arrays' +context: {a: {x: 10}, b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of object by strings' +context: {a: {x: 10}, b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of object by numbers' +context: {a: {x: 10}, b: 1} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of object by null' +context: {a: {x: 10}, b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of object by booleans' +context: {a: {x: 10}, b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of object by objects' +context: {a: {x: 10}, b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of object by arrays' +context: {a: {x: 10}, b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'unary negation of object' +context: {a: {x: 10}} +template: {$eval: '-a'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of object' +context: {a: {x: 10}} +template: {$eval: '+a'} +error: 'InterpreterError: unary + expects number' +--- +title: 'addition of array to strings' +context: {a: [1, 2], b: 'a'} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of array to numbers' +context: {a: [1, 2], b: 1} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of array to null' +context: {a: [1, 2], b: null} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of array to booleans' +context: {a: [1, 2], b: true} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of array to objects' +context: {a: [1, 2], b: {x: 1}} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'addition of array to arrays' +context: {a: [1, 2], b: [1, 2]} +template: {$eval: 'a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'subtraction of array from strings' +context: {a: [1, 2], b: 'b'} +template: {$eval: 'a-b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of array from numbers' +context: {a: [1, 2], b: 1} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of array from null' +context: {a: [1, 2], b: null} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of array from booleans' +context: {a: [1, 2], b: true} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of array from objects' +context: {a: [1, 2], b: {x: 1}} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'subtraction of array from arrays' +context: {a: [1, 2], b: [1, 2]} +template: {$eval: 'a - b'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'multiplication of array to strings' +context: {a: [1, 2], b: 'b'} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of array to numbers' +context: {a: [1, 2], b: 1} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of array to null' +context: {a: [1, 2], b: null} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of array to booleans' +context: {a: [1, 2], b: true} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of array to objects' +context: {a: [1, 2], b: {x: 1}} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'multiplication of array to arrays' +context: {a: [1, 2], b: [1, 2]} +template: {$eval: 'a * b'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'division of array by strings' +context: {a: [1, 2], b: 'b'} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of array by numbers' +context: {a: [1, 2], b: 1} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of array by null' +context: {a: [1, 2], b: null} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of array by booleans' +context: {a: [1, 2], b: true} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of array by objects' +context: {a: [1, 2], b: {x: 1}} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'division of array by arrays' +context: {a: [1, 2], b: [1, 2]} +template: {$eval: 'a / b'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'exponentiation of array by strings' +context: {a: [1, 2], b: 'b'} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of array by numbers' +context: {a: [1, 2], b: 1} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of array by null' +context: {a: [1, 2], b: null} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of array by booleans' +context: {a: [1, 2], b: true} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of array by objects' +context: {a: [1, 2], b: {x: 1}} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'exponentiation of array by arrays' +context: {a: [1, 2], b: [1, 2]} +template: {$eval: 'a ** b'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'unary negation of array' +context: {a: [1, 2]} +template: {$eval: '-a'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary plus of array' +context: {a: [1, 2]} +template: {$eval: '+a'} +error: 'InterpreterError: unary + expects number' +################################################################################ +--- +section: expression language - logic +--- +title: 'logical not (1)' +context: {tt: true, ff: false} +template: {$eval: '!tt'} +result: false +--- +title: 'logical not (2)' +context: {tt: true, ff: false} +template: {$eval: '!ff'} +result: true +--- +title: 'or operator (1)' +context: {tt: true, ff: false} +template: {$eval: 'tt || tt'} +result: true +--- +title: 'or operator (2)' +context: {tt: true, ff: false} +template: {$eval: 'tt || ff'} +result: true +--- +title: 'or operator (3)' +context: {tt: true, ff: false} +template: {$eval: 'ff || tt'} +result: true +--- +title: 'or operator (4)' +context: {tt: true, ff: false} +template: {$eval: 'ff || ff'} +result: false +--- +title: 'and operator (1)' +context: {tt: true, ff: false} +template: {$eval: 'tt && tt'} +result: true +--- +title: 'and operator (2)' +context: {tt: true, ff: false} +template: {$eval: 'tt && ff'} +result: false +--- +title: 'and operator (3)' +context: {tt: true, ff: false} +template: {$eval: 'ff && tt'} +result: false +--- +title: 'and operator (4)' +context: {tt: true, ff: false} +template: {$eval: 'ff && ff'} +result: false +--- +title: 'and operator with not operator' +context: {tt: true, ff: false} +template: {$eval: 'tt && !ff'} +result: true +--- +title: 'or operator with not operator' +context: {tt: true, ff: false} +template: {$eval: 'ff || !ff'} +result: true +--- +title: 'complex logical operation (1)' +context: {} +template: {$eval: "4 < 6 && 2 == 1 + 1"} +result: true +--- +title: 'complex logical operation (2)' +context: {} +template: {$eval: "!(4 < 6) && 2 == 1 + 1"} +result: false +--- +title: 'complex logical operation (3)' +context: {} +template: {$eval: "2 == 1 + 1 && 4 < 6"} +result: true +--- +title: 'complex logical operation (4)' +context: {} +template: {$eval: "4 >= 6 || 2 == 1 + 1"} +result: true +--- +title: 'string not' +context: {a: 'abc'} +template: {$eval: "!a"} +result: false +--- +title: 'empty string not' +context: {a: ''} +template: {$eval: "!a"} +result: true +--- +title: 'number not' +context: {a: 123} +template: {$eval: "!a"} +result: false +--- +title: 'zero not' +context: {a: 0} +template: {$eval: "!a"} +result: true +--- +title: 'null not' +context: {a: null} +template: {$eval: "!a"} +result: true +--- +title: 'object not' +context: {a: {x: 1}} +template: {$eval: "!a"} +result: false +--- +title: 'empty object not' +context: {a: {}} +template: {$eval: "!a"} +result: true +--- +title: 'array not' +context: {a: [1, 2]} +template: {$eval: "!a"} +result: false +--- +title: 'empty array not' +context: {a: []} +template: {$eval: "!a"} +result: true +--- +title: 'function not' +context: {} +template: {$eval: "!min"} +result: false +--- +title: 'string and string' +context: {a: 'abc', b: 'abc'} +template: {$eval: "a && b"} +result: true +--- +title: 'string or string' +context: {a: 'abc', b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'string and number' +context: {a: 'abc', b: 123} +template: {$eval: "a && b"} +result: true +--- +title: 'string or number' +context: {a: 'abc', b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'string and null' +context: {a: 'abc', b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'string or null' +context: {a: 'abc', b: null} +template: {$eval: "a || b"} +result: true +--- +title: 'string and boolean' +context: {a: 'abc', b: true} +template: {$eval: "a && b"} +result: true +--- +title: 'string or boolean' +context: {a: 'abc', b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'string and object' +context: {a: 'abc', b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'string or object' +context: {a: 'abc', b: {}} +template: {$eval: "a || b"} +result: true +--- +title: 'string and array' +context: {a: 'abc', b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'string or array' +context: {a: 'abc', b: []} +template: {$eval: "a || b"} +result: true +--- +title: 'number and string' +context: {a: 345, b: 'abc'} +template: {$eval: "a && b"} +result: true +--- +title: 'number or string' +context: {a: 345, b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'number and number' +context: {a: 345, b: 123} +template: {$eval: "a && b"} +result: true +--- +title: 'number or number' +context: {a: 345, b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'number and null' +context: {a: 345, b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'number or null' +context: {a: 345, b: null} +template: {$eval: "a || b"} +result: true +--- +title: 'number and boolean' +context: {a: 345, b: true} +template: {$eval: "a && b"} +result: true +--- +title: 'number or boolean' +context: {a: 345, b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'number and object' +context: {a: 345, b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'number or object' +context: {a: 345, b: {}} +template: {$eval: "a || b"} +result: true +--- +title: 'number and array' +context: {a: 345, b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'number or array' +context: {a: 345, b: []} +template: {$eval: "a || b"} +result: true +--- +title: 'null and string' +context: {a: null, b: 'abc'} +template: {$eval: "a && b"} +result: false +--- +title: 'null or string' +context: {a: null, b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'null and number' +context: {a: null, b: 123} +template: {$eval: "a && b"} +result: false +--- +title: 'null or number' +context: {a: null, b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'null and null' +context: {a: null, b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'null or null' +context: {a: null, b: null} +template: {$eval: "a || b"} +result: false +--- +title: 'null and boolean' +context: {a: null, b: true} +template: {$eval: "a && b"} +result: false +--- +title: 'null or boolean' +context: {a: null, b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'null and object' +context: {a: null, b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'null or object' +context: {a: null, b: {}} +template: {$eval: "a || b"} +result: false +--- +title: 'null and array' +context: {a: null, b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'null or array' +context: {a: null, b: []} +template: {$eval: "a || b"} +result: false +--- +title: 'boolean and string' +context: {a: true, b: 'abc'} +template: {$eval: "a && b"} +result: true +--- +title: 'boolean or string' +context: {a: true, b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'boolean and number' +context: {a: true, b: 123} +template: {$eval: "a && b"} +result: true +--- +title: 'boolean or number' +context: {a: true, b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'boolean and null' +context: {a: true, b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'boolean or null' +context: {a: true, b: null} +template: {$eval: "a || b"} +result: true +--- +title: 'boolean and boolean' +context: {a: true, b: true} +template: {$eval: "a && b"} +result: true +--- +title: 'boolean or boolean' +context: {a: true, b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'boolean and object' +context: {a: true, b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'boolean or object' +context: {a: true, b: {}} +template: {$eval: "a || b"} +result: true +--- +title: 'boolean and array' +context: {a: true, b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'boolean or array' +context: {a: true, b: []} +template: {$eval: "a || b"} +result: true +--- +title: 'object and string' +context: {a: {}, b: 'abc'} +template: {$eval: "a && b"} +result: false +--- +title: 'object or string' +context: {a: {}, b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'object and number' +context: {a: {}, b: 123} +template: {$eval: "a && b"} +result: false +--- +title: 'object or number' +context: {a: {}, b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'object and null' +context: {a: {}, b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'object or null' +context: {a: {}, b: null} +template: {$eval: "a || b"} +result: false +--- +title: 'object and boolean' +context: {a: {}, b: true} +template: {$eval: "a && b"} +result: false +--- +title: 'object or boolean' +context: {a: {}, b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'object and object' +context: {a: {}, b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'object or object' +context: {a: {}, b: {}} +template: {$eval: "a || b"} +result: false +--- +title: 'object and array' +context: {a: {}, b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'object or array' +context: {a: {}, b: []} +template: {$eval: "a || b"} +result: false +--- +title: 'array and string' +context: {a: [], b: 'abc'} +template: {$eval: "a && b"} +result: false +--- +title: 'array or string' +context: {a: [], b: 'abc'} +template: {$eval: "a || b"} +result: true +--- +title: 'array and number' +context: {a: [], b: 123} +template: {$eval: "a && b"} +result: false +--- +title: 'array or number' +context: {a: [], b: 123} +template: {$eval: "a || b"} +result: true +--- +title: 'array and null' +context: {a: [], b: null} +template: {$eval: "a && b"} +result: false +--- +title: 'array or null' +context: {a: [], b: null} +template: {$eval: "a || b"} +result: false +--- +title: 'array and boolean' +context: {a: [], b: true} +template: {$eval: "a && b"} +result: false +--- +title: 'array or boolean' +context: {a: [], b: true} +template: {$eval: "a || b"} +result: true +--- +title: 'array and object' +context: {a: [], b: {}} +template: {$eval: "a && b"} +result: false +--- +title: 'array or object' +context: {a: [], b: {}} +template: {$eval: "a || b"} +result: false +--- +title: 'array and array' +context: {a: [], b: []} +template: {$eval: "a && b"} +result: false +--- +title: 'array or array' +context: {a: [], b: []} +template: {$eval: "a || b"} +result: false +--- +title: 'short-circuit evaluation for and' +context: {} +template: {$eval: "false && b"} +result: false +--- +title: 'short-circuit evaluation for or' +context: {} +template: {$eval: "true || b"} +result: true +################################################################################ +--- +section: expression language - string operations +--- +title: 'string concatenation (1)' +context: {a: 3, b: 2} +template: {$eval: '"a" + "b"'} +result: 'ab' +--- +title: 'TypeError: string + number (1)' +context: {a: 3, b: 2} +template: {$eval: '"a" + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'TypeError: string + number (2)' +context: {a: 3, b: 2} +template: {$eval: '"" + a + b'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'TypeError: string + number (3)' +context: {a: 3, b: 2} +template: {$eval: '"" + (a + b)'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'TypeError: number + string (4)' +context: {a: 3, b: 2} +template: {$eval: '(a + b) + "abc"'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'string indexing (1)' +context: {key: '12345'} +template: {$eval: 'key[1]'} +result: '2' +--- +title: 'string indexing (2)' +context: {key: '12345'} +template: {$eval: 'key[-2]'} +result: '4' +--- +title: 'string indexing (3)' +context: {} +template: {$eval: '"12345"[1]'} +result: '2' +--- +title: 'string indexing (4)' +context: {} +template: {$eval: '"12345"[-2]'} +result: '4' +--- +title: 'string indexing (noninteger)' +context: {} +template: {$eval: '"12345"[2.5]'} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'string slicing (1)' +context: {key: '12345'} +template: {$eval: 'key[1:-1]'} +result: '234' +--- +title: 'string slicing (2)' +context: {key: '12345'} +template: {$eval: 'key[-2:]'} +result: '45' +--- +title: 'string slicing (noninteger first index)' +context: {key: '12345'} +template: {$eval: 'key[1.5:3]'} +error: 'InterpreterError: cannot perform interval access with non-integers' +--- +title: 'string slicing (noninteger second index)' +context: {key: '12345'} +template: {$eval: 'key[1:3.5]'} +error: 'InterpreterError: cannot perform interval access with non-integers' +--- +title: 'string slicing (noninteger indexes)' +context: {key: '12345'} +template: {$eval: 'key[1.5:3.5]'} +error: 'InterpreterError: cannot perform interval access with non-integers' +--- +title: 'string slicing type error (1)' +context: {key: '12345'} +template: {$eval: 'key["a":]'} +error: 'InterpreterError: cannot perform interval access with non-integers' +--- +title: 'string slicing type error (2)' +context: {key: '12345'} +template: {$eval: 'key[:"a"]'} +error: 'InterpreterError: cannot perform interval access with non-integers' +--- +title: 'string length attribute is an error' +context: {key: '12345'} +template: {$eval: 'key.length'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'string length attribute is an error even by index' +context: {key: '12345'} +template: {$eval: 'key["length"]'} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'other string attributes are not set' +context: {key: 'abc'} +template: {$eval: 'key.toUpperCase()'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'non-identifier after dot' +context: {key: {}} +template: {$eval: 'key.{'} +error: 'SyntaxError: Found: { token, expected one of: identifier' +################################################################################ +--- +section: expression language - property access +--- +title: 'property with numeric value' +context: {key: 1} +template: {$eval: 'key'} +result: 1 +--- +title: 'property with string value' +context: {key: 'a'} +template: {$eval: 'key'} +result: 'a' +--- +title: 'property with boolean value' +context: {key: true} +template: {$eval: 'key'} +result: true +--- +title: 'property with object value' +context: {key: {a: 1}} +template: {$eval: 'key'} +result: {a: 1} +--- +title: 'property with null value' +context: {key: 'null'} +template: {$eval: 'key'} +result: 'null' +--- +title: 'missing property' +context: {key: {a: 1}} +template: {$eval: 'key.b'} +error: 'InterpreterError: object has no property "b"' +--- +title: 'missing property by name' +context: {key: {a: 1}} +template: {$eval: 'key["b"]'} +result: null +--- +title: 'single property access with object value' +context: {key: {key2: 3}} +template: {$eval: 'key.key2'} +result: 3 +--- +title: 'nested property access with object value' +context: {key: {key2: {key3: {a: 1}}}} +template: {$eval: 'key.key2.key3'} +result: {a: 1} +--- +title: 'nested property access with numeric value' +context: {key: {key2: {key3: 1}}} +template: {$eval: 'key["key2"]["key3"]'} +result: 1 +--- +title: 'nested property access with dot following ]' +context: {key: {key2: {key3: 1}}} +template: {$eval: 'key["key2"].key3'} +result: 1 +--- +title: 'nested property with object in parentheses' +context: {key: {key2: true}} +template: {$eval: '(key)["key2"]'} +result: true +--- +title: 'nested property with object expression' +context: {keyid: 1, keys: [false, {key2: true}]} +template: {$eval: '(keys[keyid])["key2"]'} +result: true +--- +title: 'property access with expression value' +context: {key: abc, values: {abc: 2, def: 3}} +template: {$eval: 'values[key]'} +result: 2 +--- +title: 'property access with number' +context: + obj: {'13': 15} + key: 13 # note that this is the number 13, yet the object key is a string as required by JSON +template: {$eval: 'obj[key]'} +error: 'InterpreterError: object keys must be strings' +--- +title: 'property of number' +context: {key: 123} +template: {$eval: 'key.valueOf'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'property of null' +context: {key: null} +template: {$eval: 'key.foo'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'property of boolean' +context: {key: null} +template: {$eval: 'key.valueOf'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'property of array' +context: {key: []} +template: {$eval: 'key.valueOf'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'non-identifier after dot' +context: {key: {}} +template: {$eval: 'key.{'} +error: 'SyntaxError: Found: { token, expected one of: identifier' +################################################################################ +--- +section: expression language - array access +--- +title: 'numeric' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[0]'} +result: 1 +--- +title: 'numeric, nonzero index' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[2]'} +result: 3 +--- +title: 'numeric, noninteger index' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[2.5]'} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'arithemtic with results' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[0] + key[1] + key[2] + key[3] + key[4]'} +result: 15 +--- +title: 'string index' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key["a"]'} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'too-large index' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[999]'} +error: 'InterpreterError: index out of bounds' +--- +title: 'negative index' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[-1]'} +result: 5 +--- +title: 'nested, in property accesses' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key.key2.key3[0]'} +result: 1 +--- +title: 'nested, in property access by string' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key["key2"]["key3"][0]'} +result: 1 +--- +title: 'nested, nonzero index' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key.key2.key3[2]'} +result: 3 +--- +title: 'nested, nonzero index, in property access by string' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key["key2"]["key3"][2]'} +result: 3 +--- +title: 'nested, with arithmetic' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key.key2.key3[0] + key.key2.key3[1] + key.key2.key3[2] + key.key2.key3[3] + key.key2.key3[4]'} +result: 15 +--- +title: 'nested, with arithmetic, in property access by string' +context: {key: {key2: {key3: [1,2,3,4,5]}}} +template: {$eval: 'key["key2"]["key3"][0] + key["key2"]["key3"][1] + key["key2"]["key3"][2] + key["key2"]["key3"][3] + key["key2"]["key3"][4]'} +result: 15 +--- +title: 'indexing number' +context: {key: 123} +template: {$eval: 'key[2]'} +error: 'InterpreterError: infix: "[..]" expects object, array, or string' +--- +title: 'indexing null' +context: {key: null} +template: {$eval: 'key[2]'} +error: 'InterpreterError: infix: "[..]" expects object, array, or string' +--- +title: 'indexing boolean' +context: {key: true} +template: {$eval: 'key[2]'} +error: 'InterpreterError: infix: "[..]" expects object, array, or string' +--- +title: 'indexing object' +context: {key: {x: 10}} +template: {$eval: 'key[2]'} +error: 'InterpreterError: object keys must be strings' +--- +title: 'array length property is an error' +context: {key: [1, 3, 5]} +template: {$eval: 'key.length'} +error: 'InterpreterError: infix: . expects objects' +--- +title: 'array length property is an error even by index' +context: {key: [1, 3, 5]} +template: {$eval: 'key["length"]'} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'other array attributes are not available' +context: {key: [5, 3, 1]} +template: {$eval: 'key.sort'} +error: 'InterpreterError: infix: . expects objects' +################################################################################ +--- +section: expression language - array slicing +--- +title: 'array slicing (full slice)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[0:5]'} +result: [1,2,3,4,5] +--- +title: 'array slicing (prefix)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[0:3]'} +result: [1,2,3] +--- +title: 'array slicing (negative indices)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[-5:-1]'} +result: [1,2,3,4] +--- +title: 'array slicing (noninteger first index)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[2.5: 4]'} +error: true +--- +title: 'array slicing (noninteger last index)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[2: 3.5]'} +error: true +--- +title: 'array slicing (noninteger indexes)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[2.5: 3.5]'} +error: true +--- +title: 'array slicing (floor)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[:floor(len(key)/2)]'} +result: [1, 2] +--- +title: 'array slicing (no end index)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[-4:]'} +result: [2,3,4,5] +--- +title: 'array slicing (no start index)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[:-3]'} +result: [1,2] +--- +title: 'array slicing type error (1)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key["a":]'} +error: true +--- +title: 'array slicing type error (2)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[:"a"]'} +error: true +--- +title: 'array slicing type error (3)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key["a":"b"]'} +error: true +--- +title: 'array slicing type error (4)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key[1:"a"]'} +error: true +--- +title: 'array slicing type error (5)' +context: {key: [1,2,3,4,5]} +template: {$eval: 'key["a":2]'} +error: true +--- +title: 'slicing number' +context: {key: 123} +template: {$eval: 'key[2:]'} +error: true +--- +title: 'slicing null' +context: {key: null} +template: {$eval: 'key[2:]'} +error: true +--- +title: 'slicing boolean' +context: {key: true} +template: {$eval: 'key[2:]'} +error: true +--- +title: 'slicing object' +context: {key: {x: 10}} +template: {$eval: 'key[2:]'} +error: true +################################################################################ +--- +section: expression language - function calls +--- +title: 'function call (1)' +context: {a: 3, b: 2} +template: {$eval: 'min(a, b)'} +result: 2 +--- +title: 'function call (2)' +context: {a: 3, b: 2} +template: {$eval: 'min(3, b)'} +result: 2 +--- +title: 'function call (3)' +context: {a: 3, b: 2} +template: {$eval: 'min(a, 2)'} +result: 2 +--- +title: 'function call (4)' +context: {a: 3, b: 2} +template: {$eval: 'min(3, 2)'} +result: 2 +--- +title: 'function call (5)' +context: {a: 3, b: 2} +template: {$eval: 'max(a, b)'} +result: 3 +--- +title: 'function call (6)' +context: {a: 3, b: 2} +template: {$eval: 'max(3, b)'} +result: 3 +--- +title: 'function call (7)' +context: {a: 3, b: 2} +template: {$eval: 'max(a, 2)'} +result: 3 +--- +title: 'function call (8)' +context: {a: 3, b: 2} +template: {$eval: 'max(3, 2)'} +result: 3 +--- +title: 'function call (9)' +context: {a: 3, b: 2} +template: {$eval: 'min(a, b) + max(a, b)'} +result: 5 +--- +title: 'function call (10)' +context: {a: 3, b: 2} +template: {$eval: 'min(3, b) + max(3, b)'} +result: 5 +--- +title: 'function call (11)' +context: {a: 3, b: 2} +template: {$eval: 'min(a, 2) + max(a, 2)'} +result: 5 +--- +title: 'function call (12)' +context: {a: 3, b: 2} +template: {$eval: 'min(3, 2) + max(3, 2)'} +result: 5 +--- +title: 'function call (13)' +context: {} +template: {$let: {functions: [{$eval: min}, {$eval: max}]}, in: {$eval: 'functions[1](2, 3)'}} +result: 3 +--- +title: 'function call (14)' +context: {} +template: {$eval: '[max,min][1](5, 1)'} +result: 1 +--- +title: 'function name is not callable' +context: {function: "hi"} +template: {$eval: "function(10)"} +error: "InterpreterError: hi is not callable" +--- +title: 'parenthesized function expression' +context: {} +template: {$eval: "(min)(10, 20)"} +result: 10 +--- +title: 'dotted function expression' +context: {} +template: {$let: {negated: {max: {$eval: min}, min: {$eval: max}}}, in: {$eval: "(negated.min)(10, 20)"}} +result: 20 +################################################################################ +--- +section: expression language - in operator +--- +title: 'in operator on string, success (1)' +context: {} +template: {$eval: '"abc" in "aabc"'} +result: true +--- +title: 'in operator on string, failure (2)' +context: {} +template: {$eval: '"efg" in "aabc"'} +result: false +--- +title: 'in operator on string, success (3)' +context: {key: 'aabc'} +template: {$eval: '"abc" in key'} +result: true +--- +title: 'in operator on string, failure (4)' +context: {key: 'aabc'} +template: {$eval: '"efg" in key'} +result: false +--- +title: 'in operator on string, failure (5)' +context: {key: 'aabc'} +template: {$eval: '"2" in key'} +result: false +--- +title: 'in operator on array, success (1)' +context: {} +template: {$eval: '"abc" in [1, "abc", "def"]'} +result: true +--- +title: 'in operator on array, success (2)' +context: {} +template: {$eval: '1 in [1, "abc", "def"]'} +result: true +--- +title: 'in operator on array, success (3)' +context: {key: [1, 'abc', 'def']} +template: {$eval: '"abc" in key'} +result: true +--- +title: 'in operator on array, success (3)' +context: {key: [1, 'abc', 'def']} +template: {$eval: '1 in key'} +result: true +--- +title: 'in operator on array, failure (1)' +context: {} +template: {$eval: '"efg" in [1, "abc", "def"]'} +result: false +--- +title: 'in operator on array, failure (2)' +context: {} +template: {$eval: '2 in [1, "abc", "def"]'} +result: false +--- +title: 'in operator on array, failure (2)' +context: {key: [1, 'abc', 'def']} +template: {$eval: '"efg" in key'} +result: false +--- +title: 'in operator on array, failure (4)' +context: {key: [1, 'abc', 'def']} +template: {$eval: '2 in key'} +result: false +--- +title: 'in operator on object, success (1)' +context: {} +template: {$eval: '"a" in {"a": 1, b: 2}'} +result: true +--- +title: 'in operator on object, success (2)' +context: {key: {a: 1, b: 2}} +template: {$eval: '"a" in key'} +result: true +--- +title: 'in operator on object, success (3)' +context: {} +template: {$eval: '"3.4" in {"3.4": 1, "b": 2}'} +result: true +--- +title: 'in operator on object, failure (1)' +context: {} +template: {$eval: '"c" in {a: 1, "b": 2}'} +result: false +--- +title: 'in operator on object, failure (2)' +context: {key: {a: 1, b: 2}} +template: {$eval: '"c" in key'} +result: false +--- +title: 'in operator on object, failure (3)' +context: {} +template: {$eval: '"a" in {"3": 1, "b": 2}'} +result: false +--- +title: 'in operator on object, failure (4)' +context: {} +template: {$eval: '"3.4" in {"3": 1, "b": 2}'} +result: false +--- +title: 'TypeError: in operator on Object, error (1)' +context: {key: {a: 1, b: 2}} +template: {$eval: '[] in key'} +error: true +--- +title: 'TypeError: in operator on Object, error (2)' +context: {key: {a: 1, b: 2}} +template: {$eval: '{} in key'} +error: true +--- +title: 'TypeError: in operator on Object, error (3)' +context: {key: {a: 1, b: 2}} +template: {$eval: '1 in key'} +error: true +--- +title: 'TypeError: in operator on Array, Array not found' +context: {key: [2,3,4]} +template: {$eval: '[] in key'} +result: false +--- +title: 'TypeError: in operator on String, error (1)' +context: {key: 'hello world!'} +template: {$eval: '[] in key'} +error: true +--- +title: 'TypeError: in operator on String, error (2)' +context: {key: 'hello world!'} +template: {$eval: '{} in key'} +error: true +--- +title: 'TypeError: in operator on String, error (3)' +context: {key: 'hello world!'} +template: {$eval: '1 in key'} +error: true +--- +title: 'TypeError: in operator on Array, object not found' +context: {key: [2,3,4]} +template: {$eval: '{} in key'} +result: false +--- +title: 'no type conversion from num to string in array' +context: {} +template: {$eval: '5 in ["5", "five"]'} +result: false +--- +title: 'no type conversion from string to num in array' +context: {} +template: {$eval: '"5" in [5]'} +result: false +--- +title: 'cannot search for num in object' +context: {} +template: {$eval: '5 in {"5": "five"}'} +error: true +--- +title: 'deep equality, object on left side, found' +context: {} +template: {$eval: '{a: 45} in ["string", 46, {a: 45}]'} +result: true +--- +title: 'deep equality, object on left side, not found' +context: {} +template: {$eval: '{a: {b: 13}} in ["string", 46, {a: {b: 14}}]'} +result: false +--- +title: 'deep equality, Array on left side, found' +context: {} +template: {$eval: '[44, 45] in ["string", 46, [44, 45]]'} +result: true +--- +title: 'deep equality, Array on left side, not found' +context: {} +template: {$eval: '[44, 45] in ["string", 46, [44]]'} +result: false +--- +title: 'precedence of in over ||' +context: {a: 'a', b: 'ab'} +template: {$eval: "a in b || true"} +result: true +--- +title: 'precedence of in over &&' +context: {a: 'a', b: 'bc'} +template: {$eval: "a in b && true"} +result: false +--- +title: 'compare precedence of in and ==' +context: {a: 'a', b: 'ab', x: 5,'y': 7 } +template: {$eval: "a in b || x==y"} +result: true +################################################################################ +--- +section: expression language - comparisons +--- +title: 'equality (1)' +context: {a: 1, b: 1} +template: {$eval: '1 == 1'} +result: true +--- +title: 'equality (2)' +context: {a: 1, b: 1} +template: {$eval: '1 == 2'} +result: false +--- +title: equality (3) +context: {} +template: {$eval: '4 == 3.2 + 0.8'} +result: true +--- +title: 'equality (4)' +context: {a: 1, b: 1} +template: {$eval: 'a == b'} +result: true +--- +title: 'equality (5)' +context: {a: 1, b: 2} +template: {$eval: 'a == b'} +result: false +--- +title: object equality, true +context: {a: {x: 1,'y': 2}, b: {x: 1,'y': 2}} +template: {$eval: 'a == b'} +result: true +--- +title: object equality, false +context: {a: {x: 1,'y': 2}, b: {x: 2,'y': 2}} +template: {$eval: 'a == b'} +result: false +--- +title: object in-equality, true +context: {a: {x: 1,'y': 2}, b: {x: 2,'y': 2}} +template: {$eval: 'a != b'} +result: true +--- +title: object in-equality, false +context: {a: {x: 1,'y': 2}, b: {x: 1,'y': 2}} +template: {$eval: 'a != b'} +result: false +--- +title: complex object equality, true +context: {a: {x: 1,'y': {e: {g: {one: 1}}}}, b: {x: 1,'y': {e: {g: {one: 1}}}}} +template: {$eval: 'a == b'} +result: true +--- +title: complex object equality, false +context: {a: {x: 1,'y': {e: {g: {one: 1}}}}, b: {x: 1,'y': {e: {g: {two: 2}}}}} +template: {$eval: 'a == b'} +result: false +--- +title: complex object in-equality, true +context: {a: {x: 1,'y': {e: {g: {one: 1}}}}, b: {x: 1,'y': {e: {g: {two: 2}}}}} +template: {$eval: 'a != b'} +result: true +--- +title: complex object in-equality, false +context: {a: {x: 1,'y': {e: {g: {one: 1}}}}, b: {x: 1,'y': {e: {g: {one: 1}}}}} +template: {$eval: 'a != b'} +result: false +--- +title: 'in-equality (1)' +context: {a: 1, b: 1} +template: {$eval: '1 != 1'} +result: false +--- +title: 'in-equality (2)' +context: {a: 1, b: 1} +template: {$eval: '1 != 2'} +result: true +--- +title: 'in-equality (3)' +context: {a: 1, b: 1} +template: {$eval: 'a != b'} +result: false +--- +title: 'in-equality (4)' +context: {a: 1, b: 2} +template: {$eval: 'a != b'} +result: true +--- +title: 'less than (1)' +context: {a: 1, b: 2} +template: {$eval: '1 < 2'} +result: true +--- +title: 'less than (2)' +context: {a: 1, b: 2} +template: {$eval: '2 < 1'} +result: false +--- +title: 'less than (3)' +context: {a: 1, b: 2} +template: {$eval: '"a" < "b"'} +result: true +--- +title: 'less than (4)' +context: {a: 1, b: 2} +template: {$eval: '"b" < "a"'} +result: false +--- +title: 'less than (5)' +context: {a: 1, b: 2} +template: {$eval: 'a < b'} +result: true +--- +title: 'less than (6)' +context: {a: 1, b: 2} +template: {$eval: 'b < a'} +result: false +--- +title: 'greater than (1)' +context: {a: 1, b: 2} +template: {$eval: '2 > 1'} +result: true +--- +title: 'greater than (2)' +context: {a: 1, b: 2} +template: {$eval: '1 > 2'} +result: false +--- +title: 'greater than (3)' +context: {a: 1, b: 2} +template: {$eval: '"b" > "a"'} +result: true +--- +title: 'greater than (4)' +context: {a: 1, b: 2} +template: {$eval: '"a" > "b"'} +result: false +--- +title: 'greater than (5)' +context: {a: 1, b: 2} +template: {$eval: 'b > a'} +result: true +--- +title: 'greater than (6)' +context: {a: 1, b: 2} +template: {$eval: 'a > b'} +result: false +--- +title: 'less than equal (1)' +context: {a: 1, b: 2} +template: {$eval: "a <= b"} +result: true +--- +title: 'less than equal (2)' +context: {a: 1, b: 1} +template: {$eval: "a <= b"} +result: true +--- +title: 'less than equal (3)' +context: {a: 1, b: 2} +template: {$eval: "b <= a"} +result: false +--- +title: 'less than equal (4)' +context: {a: 1, b: 1} +template: {$eval: "b <= a"} +result: true +--- +title: 'greater than equal (1)' +context: {a: 1, b: 2} +template: {$eval: "b >= a"} +result: true +--- +title: 'greater than equal (2)' +context: {a: 1, b: 1} +template: {$eval: "a >= b"} +result: true +--- +title: 'greater than equal (3)' +context: {a: 1, b: 2} +template: {$eval: "a >= b"} +result: false +--- +title: 'greater than equal (4)' +context: {a: 1, b: 1} +template: {$eval: "a >= b"} +result: true +--- +title: 'deep object equality' +context: + a: {left: 1, right: {left: 2, right: 3}} + b: {left: 1, right: {left: 2, right: 3}} +template: {$eval: "a == b"} +result: true +--- +title: 'boolean equality' +context: {} +template: {$eval: "true == true"} +result: true +--- +title: 'null equality' +context: {a: null, b: null} +template: {$eval: "a == b"} +result: true +--- +title: 'string equality' +context: {a: 'xyz', b: 'xyz'} +template: {$eval: "a == b"} +result: true +--- +title: 'deep object inequality' +context: + a: {left: 1, right: {left: 2, right: 3}} + b: {left: 1, right: {left: 3, right: 2}} +template: {$eval: "a != b"} +result: true +--- +title: 'deep array equality' +context: + a: [1, [2, 3]] + b: [1, [2, 3]] +template: {$eval: "a == b"} +result: true +--- +title: 'deep array inequality' +context: + a: [1, [2, 3]] + b: [1, [3, 2]] +template: {$eval: "a != b"} +result: true +--- +title: ordering of string and string +context: {a: 'abc', b: 'def'} +template: {$eval: 'a < b'} +result: true +--- +title: ordering of string and number +context: {a: 'abc', b: 27} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of string and null +context: {a: 'abc', b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of string and boolean +context: {a: 'abc', b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of string and object +context: {a: 'abc', b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of string and array +context: {a: 'abc', b: []} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of number and string +context: {a: 123, b: 'def'} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of number and number +context: {a: 123, b: 27} +template: {$eval: 'a < b'} +result: false +--- +title: ordering of number and null +context: {a: 123, b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of number and boolean +context: {a: 123, b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of number and object +context: {a: 123, b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of number and array +context: {a: 123, b: []} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and string +context: {a: null, b: 'def'} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and number +context: {a: null, b: 27} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and null +context: {a: null, b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and boolean +context: {a: null, b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and object +context: {a: null, b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of null and array +context: {a: null, b: []} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and string +context: {a: true, b: 'def'} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and number +context: {a: true, b: 27} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and null +context: {a: true, b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and boolean +context: {a: true, b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and object +context: {a: true, b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of boolean and array +context: {a: true, b: []} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and string +context: {a: {}, b: 'def'} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and number +context: {a: {}, b: 27} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and null +context: {a: {}, b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and boolean +context: {a: {}, b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and object +context: {a: {}, b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of object and array +context: {a: {}, b: []} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and string +context: {a: [], b: 'def'} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and number +context: {a: [], b: 27} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and null +context: {a: [], b: null} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and boolean +context: {a: [], b: true} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and array +context: {a: [], b: {}} +template: {$eval: 'a < b'} +error: true +--- +title: ordering of array and array +context: {a: [], b: []} +template: {$eval: 'a < b'} +error: true +--- +title: equality of string and string +context: {a: 'abc', b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of string and number +context: {a: 'abc', b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of string and null +context: {a: 'abc', b: null} +template: {$eval: 'a == b'} +result: false +--- +title: equality of string and boolean +context: {a: 'abc', b: true} +template: {$eval: 'a == b'} +result: false +--- +title: equality of string and object +context: {a: 'abc', b: {}} +template: {$eval: 'a == b'} +result: false +--- +title: equality of string and array +context: {a: 'abc', b: []} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and string +context: {a: 123, b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and number +context: {a: 123, b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and null +context: {a: 123, b: null} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and boolean +context: {a: 123, b: true} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and object +context: {a: 123, b: {}} +template: {$eval: 'a == b'} +result: false +--- +title: equality of number and array +context: {a: 123, b: []} +template: {$eval: 'a == b'} +result: false +--- +title: equality of null and string +context: {a: null, b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of null and number +context: {a: null, b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of null and null +context: {a: null, b: null} +template: {$eval: 'a == b'} +result: true +--- +title: equality of null and boolean +context: {a: null, b: true} +template: {$eval: 'a == b'} +result: false +--- +title: equality of null and object +context: {a: null, b: {}} +template: {$eval: 'a == b'} +result: false +--- +title: equality of null and array +context: {a: null, b: []} +template: {$eval: 'a == b'} +result: false +--- +title: equality of boolean and string +context: {a: true, b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of boolean and number +context: {a: true, b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of boolean and null +context: {a: true, b: null} +template: {$eval: 'a == b'} +result: false +--- +title: equality of boolean and boolean +context: {a: true, b: true} +template: {$eval: 'a == b'} +result: true +--- +title: equality of boolean and object +context: {a: true, b: {}} +template: {$eval: 'a == b'} +result: false +--- +title: equality of boolean and array +context: {a: true, b: []} +template: {$eval: 'a == b'} +result: false +--- +title: equality of object and string +context: {a: {}, b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of object and number +context: {a: {}, b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of object and null +context: {a: {}, b: null} +template: {$eval: 'a == b'} +result: false +--- +title: equality of object and boolean +context: {a: {}, b: true} +template: {$eval: 'a == b'} +result: false +--- +title: equality of object and object +context: {a: {}, b: {}} +template: {$eval: 'a == b'} +result: true +--- +title: equality of object and array +context: {a: {}, b: []} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and string +context: {a: [], b: 'def'} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and number +context: {a: [], b: 27} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and null +context: {a: [], b: null} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and boolean +context: {a: [], b: true} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and object +context: {a: [], b: {}} +template: {$eval: 'a == b'} +result: false +--- +title: equality of array and array +context: {a: [], b: []} +template: {$eval: 'a == b'} +result: true +--- +title: equality of functions +context: {} +template: {$eval: 'min == min'} +result: true +--- +title: inequality of functions +context: {} +template: {$eval: 'min == max'} +result: false +--- +title: equality of function and string +context: {} +template: {$eval: 'min == "min"'} +result: false +--- +title: equality of function and number +context: {} +template: {$eval: 'min == 13'} +result: false +################################################################################ +--- +section: expression language - compound literals +--- +title: 'parse list (1)' +context: {} +template: {$eval: '[1,2,3,4]'} +result: [1,2,3,4] +--- +title: 'parse list (2)' +context: {} +template: {$eval: '[1,2,3,4][0]'} +result: 1 +--- +title: 'parse list (3)' +context: {} +template: {$eval: '[1,2,3,4][0:-1]'} +result: [1,2,3] +--- +title: 'parse list (4)' +context: {} +template: {$eval: '[1,2,3,4'} +error: true +--- +title: 'parse object (1)' +context: {key: 1} +template: {$eval: '{a: key, "b": key + 1}'} +result: {a: 1, b: 2} +--- +title: 'parse object (2)' +context: {key: 1} +template: {$eval: '{"a": key, b: key + 1}'} +result: {a: 1, b: 2} +--- +title: 'parse object (3)' +context: {key: 1} +template: {$eval: '{"a": key, "b": key + 1}'} +result: {a: 1, b: 2} +--- +title: 'parse object (4)' +context: {key: 1} +template: {$eval: '{"a": key, b: [key,key+1,key+2]}'} +result: {a: 1, b: [1,2,3]} +--- +title: 'parse object (5)' +context: {key: 1} +template: {$eval: '{a: key, "b": [key,key+1,key+2]}'} +result: {a: 1, b: [1,2,3]} +--- +title: 'parse object (6)' +context: {key: 1} +template: {$eval: '{"a": key, "b": [key,key+1,key+2]}'} +result: {a: 1, b: [1,2,3]} +--- +title: 'parse object (7)' +context: {key: 1} +template: {$eval: '{a: key, b: [key,key+1,key+2]}'} +result: {a: 1, b: [1,2,3]} +--- +title: 'parse object (8)' +context: {key: 1} +template: {$eval: '{a: key, b: min(key + 1, 1)}'} +result: {a: 1, b: 1} +--- +title: 'parse object (9)' +context: {key: 1} +template: {$eval: '{"a": key, b: min(key + 1, 1)}'} +result: {a: 1, b: 1} +--- +title: 'parse object (10)' +context: {key: 1} +template: {$eval: '{a: key, "b": min(key + 1, 1)}'} +result: {a: 1, b: 1} +--- +title: 'parse object (11)' +context: {key: 1} +template: {$eval: '{"a": key, "b": min(key + 1, 1)}'} +result: {a: 1, b: 1} +--- +title: 'parse object (12)' +context: {key: 1} +template: {$eval: '{a: key, b: key + 1'} +error: true +################################################################################ +--- +section: expression language - errors +--- +title: 'unary - type error' +context: {key: 'hello'} +template: {$eval: '-key'} +error: 'InterpreterError: unary - expects number' +--- +title: 'unary + type error' +context: {key: 'hello'} +template: {$eval: '+key'} +error: 'InterpreterError: unary + expects number' +--- +title: 'undefined variable' +context: {key: 'hello'} +template: {$eval: 'key2'} +error: 'InterpreterError: unknown context value key2' +--- +title: 'missing closing parenthesis' +context: {key1: 1, key2: 1} +template: {$eval: 'key1 + (key2 + key1'} +error: true +--- +title: 'missing opening parenthesis' +context: {key1: 1, key2: 1} +template: {$eval: 'key1 + key2 + key1)'} +error: true +--- +title: 'missing closing "' +context: {} +template: {$eval: '"hello'} +error: true +--- +title: 'missing opening "' +context: {} +template: {$eval: 'hello"'} +error: "SyntaxError: Unexpected input for 'hello\"' at '\"'" +--- +title: 'Infix + type error' +context: {} +template: {$eval: 'true + false'} +error: 'InterpreterError: infix: + expects numbers/strings + numbers/strings' +--- +title: 'Infix - type error' +context: {} +template: {$eval: '"hello" - 3'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'Infix * type error' +context: {} +template: {$eval: '"hello" * 3'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'Infix / type error' +context: {} +template: {$eval: '"hello" / 3'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'Infix - type error' +context: {} +template: {$eval: '3 - "hello"'} +error: 'InterpreterError: infix: - expects number - number' +--- +title: 'Infix * type error' +context: {} +template: {$eval: '3 * "hello"'} +error: 'InterpreterError: infix: * expects number * number' +--- +title: 'Infix / type error' +context: {} +template: {$eval: '3 / "hello"'} +error: 'InterpreterError: infix: / expects number / number' +--- +title: 'Infix ** type error' +context: {} +template: {$eval: '"hello" ** 3'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'Infix ** type error' +context: {} +template: {$eval: '3 ** "hello"'} +error: 'InterpreterError: infix: ** expects number ** number' +--- +title: 'Infix < type error' +context: {} +template: {$eval: '"hello" < 3'} +error: 'InterpreterError: infix: < expects numbers/strings < numbers/strings' +--- +title: 'Infix > type error' +context: {} +template: {$eval: '"hello" > 3'} +error: 'InterpreterError: infix: > expects numbers/strings > numbers/strings' +--- +title: 'Infix <= type error' +context: {} +template: {$eval: '"hello" <= 3'} +error: 'InterpreterError: infix: <= expects numbers/strings <= numbers/strings' +--- +title: 'Infix >= type error' +context: {} +template: {$eval: '"hello" >= 3'} +error: 'InterpreterError: infix: >= expects numbers/strings >= numbers/strings' +--- +title: 'Infix < type error' +context: {} +template: {$eval: '3 < "hello"'} +error: 'InterpreterError: infix: < expects numbers/strings < numbers/strings' +--- +title: 'Infix > type error' +context: {} +template: {$eval: '3 > "hello"'} +error: 'InterpreterError: infix: > expects numbers/strings > numbers/strings' +--- +title: 'Infix <= type error' +context: {} +template: {$eval: '3 <= "hello"'} +error: 'InterpreterError: infix: <= expects numbers/strings <= numbers/strings' +--- +title: 'Infix >= type error' +context: {} +template: {$eval: '3 >= "hello"'} +error: 'InterpreterError: infix: >= expects numbers/strings >= numbers/strings' +--- +title: 'Infix access array or string with non-integer type error' +context: {extra: {attributes: 'a string!'}} +template: {$if: "extra.attributes['someattr'] == 'x'", then: true} +error: 'InterpreterError: should only use integers to access arrays or strings' +--- +title: 'Nested error has appropriate message' +context: {} +template: {foo: [1, {"123": [{$eval: 10}]}]} +error: 'TemplateError at template.foo[1]["123"][0]: $eval must be given a string expression' +--- +title: 'object with missing value ' +context: {} +template: {$eval: '{a: 1, "b": }'} +error: "SyntaxError: Found: } token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: 'object missing key and value after comma' +context: {} +template: {$eval: '{a: 1,'} +error: "SyntaxError: Unexpected end of input" +--- +title: 'list with missing first value' +context: {} +template: {$eval: '[,2,3]'} +error: "SyntaxError: Found: , token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: 'list with missing value' +context: {} +template: {$eval: '[1,,3]'} +error: "SyntaxError: Found: , token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: 'empty brackets in property access' +context: {a: "0123456789"} +template: {$eval: 'a[]'} +error: "SyntaxError: Found: ] token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: 'function call with missing closing bracket' +context: {} +template: {$eval: 'max(2, 0'} +error: "SyntaxError: Unexpected end of input" +--- +title: 'function call with missing argument in brackets' +context: {} +template: {$eval: 'max(, 0)'} +error: "SyntaxError: Found: , token, expected one of: !, (, +, -, [, false, identifier, null, number, string, true, {" +--- +title: 'uncalled function' +context: {} +template: {$eval: 'fromNow'} +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: 'list expression with uncalled functions' +context: {} +template: {$eval: '[min, max]'} +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: 'list with uncalled function inside' +context: {} +template: [{$eval: 'min'}] +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: 'object containing uncalled function' +context: {} +template: {maximum: {$eval: 'max'}} +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: 'deep data structure with uncalled functions' +context: {} +template: [{minimum: {$eval: 'min'}}, {maximum: {$eval: 'max'}}] +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: '$json with an uncalled function' +context: {} +template: {$json: {$eval: 'lowercase'}} +error: "TemplateError: evaluated template contained uncalled functions" +--- +title: '$json with deep uncalled functions' +context: {} +template: {$json: [{minimum: {$eval: 'min'}}, {maximum: {$eval: 'max'}}]} +error: "TemplateError: evaluated template contained uncalled functions" +################################################################################ +--- +section: Regression tests +--- +title: issue 354 +template: {$eval: 'max(3, 2)'} +context: {} +result: 3