View Source Alembic.Parser.Expression (alembic v0.2.0)
Parses the raw string content of a Liquid expression — everything that can
appear inside {{ ... }} output tags and {% if ... %} / {% for ... in ... %} conditions — into an Alembic.AST.expr() node.
Grammar (see docs/grammar.md):
expr = or_expr ;
or_expr = and_expr , { "or" , and_expr } ;
and_expr = not_expr , { "and" , not_expr } ;
not_expr = [ "not" ] , comparison ;
comparison = filtered_primary , [ compare_op , filtered_primary ] ;
filtered_primary = primary , { filter } ;
primary = variable | literal ;
filter = "|" , IDENT , [ ":" , expr , { "," , expr } ] ;The barewords empty and blank are contextual keywords: a bare
empty/blank used as a comparison operand (for any comparison operator)
parses to {:keyword, :empty} / {:keyword, :blank}. They are still
equality-only at render time (==/!=); other operators return
{:keyword_requires_equality, ...}. Outside comparison operands, bare
empty/blank stay ordinary variable paths, so {{ empty }} and
{% assign empty = 1 %} still resolve a variable named empty.
Filters bind tighter than comparison and logical operators — this lets a
bare "name | upcase" parse on its own (used for output tags) while still
allowing filtered operands inside a condition, e.g. x | size > 0.
Summary
Functions
Parses the raw string content of an output tag or a tag condition into an
Alembic.AST.expr().
Like parse_list/1, but bare empty/blank values become keyword
operands. Used for {% when %} values, which are compared against the
case subject with == semantics and therefore accept the keywords.
Parses a comma-separated list of expressions (the expr_list production) —
the values of {% when a, b, c %} and {% cycle a, b %}.
Types
Functions
@spec parse(String.t()) :: {:ok, Alembic.AST.expr()} | {:error, reason()}
Parses the raw string content of an output tag or a tag condition into an
Alembic.AST.expr().
Examples
iex> Alembic.Parser.Expression.parse("user.name")
{:ok, {:variable, ["user", "name"]}}
iex> Alembic.Parser.Expression.parse("name | upcase")
{:ok, {:filter_chain, {:variable, ["name"]}, [{:filter, "upcase", []}]}}
iex> Alembic.Parser.Expression.parse("x > 0 and not skip")
{:ok,
{:logical, :and, {:compare, :gt, {:variable, ["x"]}, {:literal, 0}},
{:not, {:variable, ["skip"]}}}}
@spec parse(String.t(), boolean()) :: {:ok, Alembic.AST.expr()} | {:error, reason()}
Like parse/1, but allow_ranges: true permits (from..to) range
literals. Ranges are restricted to the {% for %} iterable position;
calling parse/1 (or parse/2 without the flag) on a range returns
{:error, :range_not_allowed}.
@spec parse_keyword_list(String.t()) :: {:ok, [Alembic.AST.expr()]} | {:error, reason()}
Like parse_list/1, but bare empty/blank values become keyword
operands. Used for {% when %} values, which are compared against the
case subject with == semantics and therefore accept the keywords.
@spec parse_list(String.t()) :: {:ok, [Alembic.AST.expr()]} | {:error, reason()}
Parses a comma-separated list of expressions (the expr_list production) —
the values of {% when a, b, c %} and {% cycle a, b %}.
Commas that belong to a filter's own argument list are consumed by the
filter parser, so splitting happens only at expression-list boundaries:
x | append: "a", "b" is one filtered expression (two filter arguments),
while 1, 2, 3 is three values.
Examples
iex> Alembic.Parser.Expression.parse_list("1, 2, 3")
{:ok, [{:literal, 1}, {:literal, 2}, {:literal, 3}]}
iex> Alembic.Parser.Expression.parse_list(~s(x | append: "a", "b"))
{:ok,
[{:filter_chain, {:variable, ["x"]},
[{:filter, "append", [{:literal, "a"}, {:literal, "b"}]}]}]}