Elex.Parser (Elex v0.2.1)

View Source

Parses Elex expression strings into AST tuples.

The parser is built with NimbleParsec and supports operator precedence, function calls, literals, and variables. Parsing optionally validates the AST against a Elex.Context via Elex.Validator.

Syntax overview

Literals: decimal numbers (3.14, -5), booleans (true, false, yes, no), null (null), strings ("hello")

Variables: lowercase identifiers (x, my_var)

Operators (by precedence, lowest to highest):

  • or
  • and
  • ==, !=, <, >, <=, >= (operands must share a type; strings use lexicographic order)
  • +, -
  • *, /, %
  • not (unary)
  • - (unary)

Functions: name(arg1, arg2) — built-ins include abs, between, ceil, clamp, coalesce, concat, contains, ends_with, floor, if, length, lower, max, min, mod, pi, pow, rem, round, sqrt, starts_with, trim, and upper. min, max, and coalesce accept two or more arguments. See modules under Elex.Functions.*.

Short-circuit: and, or, and if(condition, a, b) skip evaluating operands or branches that cannot affect the result.

Parentheses group sub-expressions: (1 + 2) * 3

Examples

context = Elex.new_context() |> Elex.add_variable("x", 10)
Elex.Parser.parse("x + 5", context)
#=> {:ok, {:+, [{:var, "x"}, #Decimal<5>]}, :decimal}

Summary

Types

Low-level parse details returned by debug/1.

Functions

Parses an expression and returns the raw, low-level parser state.

Parses an expression string and optionally validates the resulting AST against a context.

Types

debug_info()

@type debug_info() :: %{
  expression: String.t(),
  status: :ok | :error,
  ast: term() | nil,
  reason: String.t() | nil,
  consumed: String.t(),
  rest: String.t(),
  line: pos_integer(),
  column: non_neg_integer(),
  byte_offset: non_neg_integer()
}

Low-level parse details returned by debug/1.

  • :expression - the original input string
  • :status - :ok when the whole input parsed, :error otherwise
  • :ast - the parsed AST on success, nil on error
  • :reason - the raw NimbleParsec error message on error, nil on success
  • :consumed - the leading portion of the input the parser accepted
  • :rest - the unconsumed remainder at the furthest position reached
  • :line / :column - 1-based line and 0-based column of that position. NimbleParsec does not track intra-line columns for this grammar, so :column is 0 for single-line expressions; use :byte_offset to locate the position instead.
  • :byte_offset - byte offset of that position into the input

Functions

debug(expression, opts \\ [])

@spec debug(
  String.t(),
  keyword()
) :: debug_info()

Parses an expression and returns the raw, low-level parser state.

This is a development and debugging aid: it exposes exactly what the underlying NimbleParsec parser produced (including the raw error message, how far it got, and what input was left over) without validating the AST against a context or translating errors into human-readable messages.

Use parse/3 for normal parsing.

Options

  • :max_depth - Maximum parenthesis/function-call nesting depth. Expressions nested more deeply are rejected before parsing (mirroring parse/3), guarding against resource exhaustion from pathologically nested input. The returned map has status: :error with the same reason parse/3 reports. Must be a non-negative integer; an invalid value yields an error map rather than silently disabling the guard. Defaults to 16.

Returns

A debug_info map. See its documentation for the fields.

Examples

iex> info = Elex.Parser.debug("( 1 + 2")
iex> info.status
:error
iex> info.rest
"( 1 + 2"

iex> info = Elex.Parser.debug("1 + 2")
iex> info.status
:ok
iex> info.rest
""

parse(expression, context, opts \\ [])

@spec parse(String.t(), Elex.Context.t(), keyword()) ::
  {:ok, term(), atom()} | {:error, String.t()}

Parses an expression string and optionally validates the resulting AST against a context.

Parameters

  • expression - The expression string to parse
  • context - A Elex.Context with variables and functions
  • opts - Keyword list of options (see below)

Options

  • :validate - Whether to validate the AST against the context. Defaults to true. When false, the returned type is nil.
  • :max_depth - Maximum parenthesis/function-call nesting depth. Expressions nested more deeply are rejected with an error before parsing, guarding against resource exhaustion from pathologically nested input. Defaults to 16.

Returns

  • {:ok, ast, type} - Parsed (and optionally validated) AST with result type
  • {:error, reason} - Parse or validation error message

Examples

context = Elex.new_context() |> Elex.add_variable("x", 10)
Elex.Parser.parse("x + 5", context)
#=> {:ok, {:+, [{:var, "x"}, #Decimal<5>]}, :decimal}

Elex.Parser.parse("unknown_var", context)
#=> {:error, "variable 'unknown_var' does not exist"}