Predicator.Evaluator (predicator v2.2.0)

View Source

Stack-based evaluator for predicator instructions.

The evaluator executes a list of instructions using a stack machine approach. Instructions operate on a stack, with the most recent values at the top (head of list).

Supported instruction types:

  • ["lit", value] - Push literal value onto stack
  • ["load", variable_name] - Load variable from context onto stack
  • ["compare", operator] - Compare top two stack values with operator
  • ["and"] - Logical AND of top two boolean values
  • ["or"] - Logical OR of top two boolean values
  • ["not"] - Logical NOT of top boolean value
  • ["in"] - Membership test (element in collection)
  • ["contains"] - Membership test (collection contains element)
  • ["add"] - Add top two integer values
  • ["subtract"] - Subtract top two integer values
  • ["multiply"] - Multiply top two integer values
  • ["divide"] - Divide top two integer values (integer division)
  • ["modulo"] - Modulo operation on top two integer values
  • ["unary_minus"] - Negate top integer value
  • ["unary_bang"] - Logical NOT of top boolean value
  • ["bracket_access"] - Pop key and object, push object[key] result
  • ["call", function_name, arg_count] - Call function with arguments from stack

Summary

Types

t()

Internal evaluator state

Functions

Evaluates a list of instructions with the given context and options.

Evaluates a list of instructions with the given context and options, raising on errors.

Runs the evaluator until it halts or encounters an error.

Executes a single instruction step.

Types

t()

@type t() :: %Predicator.Evaluator{
  context: Predicator.Types.context(),
  functions: %{required(binary()) => {non_neg_integer(), function()}},
  halted: boolean(),
  instruction_pointer: non_neg_integer(),
  instructions: Predicator.Types.instruction_list(),
  stack: [Predicator.Types.value()]
}

Internal evaluator state

Functions

evaluate(instructions, context \\ %{}, opts \\ [])

Evaluates a list of instructions with the given context and options.

Returns the top value on the stack when evaluation completes, or an error if something goes wrong.

Parameters

  • instructions - List of instructions to execute
  • context - Context map with variable bindings (default: %{})
  • opts - Options keyword list:
    • :functions - Map of custom functions %{name => {arity, function}}

Examples

iex> Predicator.Evaluator.evaluate([["lit", 42]], %{})
42

iex> Predicator.Evaluator.evaluate([["load", "score"]], %{"score" => 85})
85

# With custom functions
iex> custom_functions = %{"double" => {1, fn [n], _context -> {:ok, n * 2} end}}
iex> instructions = [["lit", 21], ["call", "double", 1]]
iex> Predicator.Evaluator.evaluate(instructions, %{}, functions: custom_functions)
42

evaluate!(instructions, context \\ %{}, opts \\ [])

Evaluates a list of instructions with the given context and options, raising on errors.

Similar to evaluate/3 but raises an exception for error results instead of returning error tuples. Follows the Elixir convention of bang functions.

Examples

iex> Predicator.Evaluator.evaluate!([["lit", 42]], %{})
42

iex> Predicator.Evaluator.evaluate!([["load", "score"]], %{"score" => 85})
85

# With custom functions
iex> custom_functions = %{"double" => {1, fn [n], _context -> {:ok, n * 2} end}}
iex> instructions = [["lit", 21], ["call", "double", 1]]
iex> Predicator.Evaluator.evaluate!(instructions, %{}, functions: custom_functions)
42

run(evaluator)

@spec run(t()) :: {:ok, t()} | {:error, struct()}

Runs the evaluator until it halts or encounters an error.

Returns {:ok, final_state} on success or {:error, reason} on failure.

step(evaluator)

@spec step(t()) :: {:ok, t()} | {:error, term()}

Executes a single instruction step.

Returns the updated evaluator state or an error.

types_match(a, b)

(macro)