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

Parse a block and return the AST

Parse an expression and return the AST

Functions

expression(binary, opts \\ [])

@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}

parse(binary, opts \\ [])

@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}

to_double_quoted_string(charlist)