expry

HINT You can use the search bar to try these expressions. It recognizes the syntax below.

'Binary Objects' is a fast schemaless binary format for data, that focus on fast filtering and selecting parts of the information. The following data types are supported:

  • null;

  • bool;

  • int64;

  • float;

  • double;

  • string;

  • array;

  • object.

Expressions

Expressions over binary objects are compiled to byte code, and can be transmitted over the network. This bytecode can be quicky evaluated, as the bytecode is optimized on the way the binary objects are stored on a low level. Keys inside objects are stored in an ordered way. If keys are not needed anymore for evaluation of the current expression, they are permanently skipped.

  • Constants: null, false, true, PI, E, LN2, LN10, decimal numbers, 0x..., 0b..., ...f, strings with 'string' or "string".

  • Special constants:

    • hex strings: x"abcd";

    • raw strings: r##"(something)"##. Between r and " there can be additional # chars: e.g. r##"foobar"##, for the string "foobar".

  • Object expression with { fields? }, with optional fields, individual fields seperated by ,:

    • fields can be name: expr with expr an expression or a primary data type (see above);

    • fields can be "name": expr with expr an expression or a primary data type (see above);

    • fields can be field (or field???), which copies the field from the this object;

    • fields can be (expr): expr to dynamically generate an field name (must be a string), e.g. {(somefield): 42} (results in {x: 42} if somefield is "x").

  • Array expressions: [ expressions? ], with the optional expressions which are one or more expressions delimited by ,. Example: [ 42+42, 37+37 ].

  • Arithmetic operators: +, -, *, /, ** (pow), % (mod).

  • Bitwise operators: |, &, ^ (xor), <<, >>

  • Logical operators: &&, ||, a ? b : c, ==, !=, >, >=, <, <=.

  • Special this field, to signify current object.

  • Length operator:

    • field.len() which result in the length of the field if it is a string (number of bytes), array (number of elements), or object (number of key-values).

  • String operators:

    • a .. b: concat strings a and b;

    • a *= b: true if string a contains with string b

    • a $= b: true if string a ends with string b

    • a ^= b: true if string a starts with string b

  • Field operators:

    • a.b.c.d is supported to access subfields;

    • a[b][c][d] is supported for dynamic subfields;

  • Error operators:

    • try operator: a ??? b: if there is an error during evaluation of a (like an undefiend field, or division by zero). The shorthand a ??? is equavilent to a ??? null. Alternative syntax is try(a, b) and try(a).

    • not-null-else operator: a ?? b: if a is null, return b.

  • defined(x) and undefined(x): checks if value is (un)defined (such as a field lookup).

  • isnull(x) checks if x is equal to null.

  • Math functions:

    • pow(number)

    • log2(number)

    • log10(number)

    • log(number)

    • sqrt(number)

    • sin(number)

    • cos(number)

    • tan(number)

    • abs(number)

    • floor(number)

    • ceil(number)

    • trunc(number)

    • round(number)

  • String methods:

    • .trim()

    • .lower()

    • .upper()

    • .hex()

    • .htmlescape()

    • .urlescape()

    • .sub(int[, int]) (third argument is length of resulting string, default max int)

    • .basename()

    • .dirname()

    • .splitn(max, split_on) (split_on is the splitting string, max is the max number of elements in the resulting array), results in an array of strings

  • Type functions

    • tostring(any)

    • tointeger(any)

    • tofloat(any)

    • todouble(any)

    • isnull(any)

    • isbool(any)

    • isnumber(any)

    • isinteger(any)

    • isfloat(any)

    • isdouble(any)

    • isstring(any)

    • isarray(any)

    • isobject(any)

User defined functions

During evaluation, there is also the possibility to add user defined functions. These user defined functions are only known at evaluation time, therefore there is no static type checking in place. Only runtime errors are generated if the number of arguments or type of arguments do not match.

Wishlist

  • dynamic slicing expressions for arrays (and maybe objects), with an expression filtering individual fields;

  • ...


Binary Object expressions can be used instead of values as above (think of expressions, functional calls, selectors, etc). This utility supports also Lua in the templates. Prefix anywhere a value is accepted with lua: to run Lua code (with current value in this).

There are a couple of special functions added to the Binary Object expressions:

  • string compile(string template, [any context])
    Compiles a string to a dynamic Mustache template that can be evaluated, and evaluates the defaults using the optional context context (otherwise empty context is used).

  • string eval(string compiled_template, any context)
    Evaluates a dynamic Mustache template using the context context.

  • void set(string key, any value)

  • any get(string key)
    Sets/retrieves a global value (useful for figure numbers etc).

  • string filehash(string path)

  • string filewithhash(string path)
    Calculates the xxhash32 for the contents of the file specified by path (relative to the --base flag). Useful to support caching with a long TTL: setting the hash as query makes the URL unique for the content (if the content changes). The function call filewithhash(path) prints path?hash.