Expression.V2.Parser (expression v2.41.4)
A NimbleParsec parser for FLOIP expressions.
FLOIP Expressions consist of plain text and of blocks. Plain text is returned untouched but blocks are evaluated.
Blocks are prefixed with an @
sign. Blocks can either have expressions between brackets or
be used in a shorthand form when wanting to use a single function or variable substitution.
As an example, the following are identical:
@(now())
and@now()
@contact.name
and@(contact.name)
However, a full expression needs to be within brackets:
Tomorrow's is @(today().day + 1)
This parses it into an Abstract Syntax Tree (AST) which follows a style much like a Lisp would.
It parses expressions in Infix notation such as
1 + 1
and parses it into lists where the operator is the first element and the second element
is the list of arguments for the operator.
["+", [1, 1]]
Functions are expressed as:
{"function name", [arg1, arg2]}
Until we have a fixed scope of allowed functions, or if we can dynamically look up whether an
atom
is a function or a variable reference, we will need to rely on tuples to represent functions
as otherwise the system has no means to distinguish the following AST as being a function call
or a list as a variable:
["echo", [1, 2, 3]]
Without being able to say ahead of time whether or not echo/1
is a known function, the
system cannot reliable determine whether the result of this AST should be ["echo", [1, 2, 3]]
or the result of echo(1, 2, 3)
.
Variable references are single values.
"contact"
This module provides two functions for parsing. parse/2
which will parse a full FLOIP expression
including text and blocks, and expression/2
which will parse expression blocks.
Internally parse/2
refers to the same parsers as expression/2
for things that are expressions.
Summary
Functions
@spec expression(binary(), keyword()) :: {:ok, [term()], rest, context, line, byte_offset} | {:error, reason, rest, context, line, byte_offset} when line: {pos_integer(), byte_offset}, byte_offset: pos_integer(), rest: binary(), reason: String.t(), context: map()
Parse a block and return the AST
Example
iex> Expression.V2.Parser.expression("contact.age + 1")
{:ok, [{"+", [{"__property__", ["contact", "age"]}, 1]}], "", %{}, {1, 0}, 15}
@spec parse(binary(), keyword()) :: {:ok, [term()], rest, context, line, byte_offset} | {:error, reason, rest, context, line, byte_offset} when line: {pos_integer(), byte_offset}, byte_offset: pos_integer(), rest: binary(), reason: String.t(), context: map()
Parse an expression and return the AST
Example
iex> Expression.V2.Parser.parse("hello @world the time is @now()")
{:ok, ["hello ", ["world"], " the time is ", [{"now", []}]], "", %{}, {1, 0}, 31}