Expression.V2 (expression v2.41.4)
A second attempt at the parser, hopefully a little easier to read & maintain.
parse/1
parsed an Expression into AST.
eval/3
evaluates the given AST using the context supplied.
For details on how this is done please read Expression.V2.Parser
and
Expression.V2.Compile
.
This parser & evaluator supports the following:
- strings either double or single quoted.
- integers such as
1
,2
,40
,55
- floats such as
3.141592653589793
- booleans which can be written in any mixed case such as
tRue
orTRUE
,False
etc Range.t
such as1..10
, also with steps1..10//2
Date.t
such as2022-01-01
which is parsed into~D[2022-01-01]
Time.t
such as10:30
which is parsed into~T[10:30:00]
- ISO formatted
DateTime.t
such as2022-05-24T00:00:00
which is parsed into~U[2022-05-24 00:00:00.0Z]
- US formatted
DateTime.t
such as01-02-2020 23:23:23
which is parsed into~U[2020-02-01T23:23:23Z]
- Lists of any of the above, such as
[1, 2, 3]
or[1, 1.234, "john"]
- Reading properties off of nested objects such as maps with a full stop, such as
contact.name
returning"Doe"
from%{"contact" => %{"name" => "Doe"}}
- Reading attributes off of maps, such as
contact[the_key]
which returns"Doe"
from%{"contact" => %{"name" => "Doe"}, "the_key" => "name"}
- Anonymous functions with
&
and&1
as capture operators,&(&1 + 1)
is an anonymous function that increments the input by 1.
The result of a call to eval/3
is a list of typed evaluated items. It is up to the integrating library to determine how
best to convert these into a final end user representation.
Examples
iex> alias Expression.V2
iex> V2.eval("the date is @date(2022, 2, 20)")
["the date is ", ~D[2022-02-20]]
iex> V2.eval("the answer is @true")
["the answer is ", true]
iex> V2.eval("22 divided by 7 is @(22 / 7)")
["22 divided by 7 is ", 3.142857142857143]
iex> V2.eval(
...> "Hello @proper(contact.name)! Looking forward to meet you @date(2023, 2, 20)",
...> V2.Context.new(%{"contact" => %{"name" => "mary"}})
...> )
["Hello ", "Mary", "! Looking forward to meet you ", ~D[2023-02-20]]
iex> V2.eval("@map(1..3, &date(2023, 1, &1))")
[[~D[2023-01-01], ~D[2023-01-02], ~D[2023-01-03]]]
iex> V2.eval(
...> "Here is the multiplication table of @number: @(map(1..10, &(&1 * number)))",
...> V2.Context.new(%{"number" => 5})
...> )
[
"Here is the multiplication table of ",
5,
": ",
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
]
Summary
Functions
Return the code generated for the Abstract Syntax tree or Expression string provided.
Return the default value for a potentially complex value.
Evaluate a string with expressions against a given context
Evaluate an expression and cast all items to strings before joining the full result into a single string value to be returned.
Evaluate a parsed Expression against a given context
Evaluate a string with an expression block against a context
Evaluate the given AST against a given context
Parse a string with expressions into AST for the compile step
Parse a string with an expression block into AST for the compile step
This function is referenced by Expression.V2.Compile
to
make access to values in Maps or Lists easier
Functions
Return the code generated for the Abstract Syntax tree or Expression string provided.
Return the default value for a potentially complex value.
Complex values can be Maps that have a __value__
key, if that's
returned then we can to use the __value__
value when eval'ing against
operators or functions.
@spec eval(expression :: String.t(), context :: Expression.V2.Context.t()) :: [term()]
Evaluate a string with expressions against a given context
@spec eval_as_string(String.t(), Expression.V2.Context.t()) :: String.t()
Evaluate an expression and cast all items to strings before joining the full result into a single string value to be returned.
This calls eval/2
internally, maps the results with default_value/2
followed by stringify/1
and then joins them.
@spec eval_ast([term()], context :: Expression.V2.Context.t()) :: [term()]
Evaluate a parsed Expression against a given context
@spec eval_block(String.t(), context :: Expression.V2.Context.t()) :: term() | {:error, reason :: String.t(), bad_parts :: String.t()}
Evaluate a string with an expression block against a context
@spec eval_block_ast([term()], context :: Expression.V2.Context.t()) :: [term()]
Evaluate the given AST against a given context
@spec parse(String.t()) :: {:ok, [term()]} | {:error, reason :: String.t(), bad_parts :: String.t()}
Parse a string with expressions into AST for the compile step
@spec parse_block(String.t()) :: {:ok, [term()]} | {:error, reason :: String.t(), bad_parts :: String.t()}
Parse a string with an expression block into AST for the compile step
This function is referenced by Expression.V2.Compile
to
make access to values in Maps or Lists easier