Core type definitions for the Predicator library.
This module defines all the fundamental types used throughout the Predicator system for instructions, evaluation contexts, and results.
Summary
Types
The evaluation context containing variable bindings.
A duration representing a time span.
The internal state of the stack machine evaluator.
A single instruction in the stack machine.
A list of instructions that form a complete program.
The internal result of evaluating a predicate from Evaluator functions.
Location path for assignment expressions.
Result type for location expression evaluation.
A source position: 1-based line and column of the token that defines an AST node.
Maps a 0-based instruction index to the source position of the AST node that
emitted it. Produced by Predicator.Compiler.to_instructions_with_positions/2;
never part of the instruction list itself, so interchange and stored compiled
artifacts are unaffected.
The result of evaluating a predicate from public API functions.
SCXML-compatible error result for enhanced error handling.
SCXML-compatible result type for value expressions.
A single value that can be used in predicates.
Types
The evaluation context containing variable bindings.
Context maps variable names (strings or atoms) to their values. Both string and atom keys are supported for flexibility.
Examples
%{"score" => 85, "name" => "Alice"}
%{score: 85, name: "Alice"}
@type duration() :: %{ years: non_neg_integer(), months: non_neg_integer(), weeks: non_neg_integer(), days: non_neg_integer(), hours: non_neg_integer(), minutes: non_neg_integer(), seconds: non_neg_integer(), milliseconds: non_neg_integer() }
A duration representing a time span.
Duration is represented as a map with fields for different time units:
years- number of years (default: 0)months- number of months (default: 0)weeks- number of weeks (default: 0)days- number of days (default: 0)hours- number of hours (default: 0)minutes- number of minutes (default: 0)seconds- number of seconds (default: 0)
Examples
%Duration{days: 3, hours: 8} # 3 days 8 hours
%Duration{weeks: 2} # 2 weeks
%Duration{minutes: 30} # 30 minutes
@type evaluator_state() :: %{ instructions: instruction_list(), instruction_pointer: non_neg_integer(), stack: [value()], context: context(), halted: boolean() }
The internal state of the stack machine evaluator.
Contains:
instructions- list of instructions to executeinstruction_pointer- current position in instruction liststack- evaluation stack (top element is head of list)context- variable bindingshalted- whether execution has stopped
A single instruction in the stack machine.
Instructions are lists where the first element is the operation name and remaining elements are arguments.
Currently supported instructions:
["lit", value()]- Push literal value onto stack["load", binary()]- Load variable from context onto stack["compare", binary()]- Compare top two stack values with operator["and"]- Logical AND of top two boolean values["or"]- Logical OR of top two boolean values["jump_if_falsy_or_pop", integer()]- Jump forward if top is falsy (leaving it), else pop["jump_if_true_or_pop", integer()]- Jump forward if top is true (leaving it), else pop["not"]- Logical NOT of top boolean value["in"]- Membership test (element in collection)["contains"]- Membership test (collection contains element)["add"]- Pop two values, add them, push result["subtract"]- Pop two values, subtract them, push result["multiply"]- Pop two values, multiply them, push result["divide"]- Pop two values, divide them, push result["modulo"]- Pop two values, modulo operation, push result["unary_minus"]- Pop one value, negate it, push result["unary_bang"]- Pop one value, logical NOT it, push result["bracket_access"]- Pop key and object, push object[key] result["object_new"]- Push new empty object onto stack["object_set", binary()]- Pop value and object, set object[key] = value, push object["make_list", integer()]- Pop n values, push them as a list["call", binary(), integer()]- Call built-in function with arguments from stack
No instruction carries a source position. Positions travel in a separate
position_table/0, produced alongside the instruction list by
Predicator.Compiler.to_instructions_with_positions/2, so the instruction
format stays exactly what the Ruby and JavaScript siblings interchange
(ADR-0001).
Examples
["lit", 42] # Push literal 42 onto stack
["load", "score"] # Load variable 'score' from context
["compare", "GT"] # Pop two values, compare with >, push result
["and"] # Pop two boolean values, push AND result
["or"] # Pop two boolean values, push OR result
["jump_if_falsy_or_pop", 3] # If top is false/:undefined, jump 3 forward, else pop
["jump_if_true_or_pop", 3] # If top is true, jump 3 forward, else pop
["not"] # Pop one boolean value, push NOT result
["add"] # Pop two values, add them, push result
["subtract"] # Pop two values, subtract them, push result
["multiply"] # Pop two values, multiply them, push result
["divide"] # Pop two values, divide them, push result
["modulo"] # Pop two values, modulo them, push result
["unary_minus"] # Pop one value, negate it, push result
["unary_bang"] # Pop one value, logical NOT it, push result
["bracket_access"] # Pop key and object, push object[key]
["object_new"] # Push new empty object onto stack
["object_set", "name"] # Pop value and object, set object["name"] = value, push object
["make_list", 2] # Pop 2 values, push them as a 2-element list
["call", "len", 1] # Pop 1 argument, call len function, push result
@type instruction_list() :: [instruction()]
A list of instructions that form a complete program.
Instructions are executed in order by the stack machine.
The internal result of evaluating a predicate from Evaluator functions.
Returns:
value()- the final evaluation result value{:error, term()}- evaluation error with details
@type location_path() :: [binary() | non_neg_integer()]
Location path for assignment expressions.
Represents the path to an assignable location in nested data structures:
- Simple property:
["user", "name"] - Array index:
["items", 0, "price"] - Dynamic property:
["user", "settings", "theme"](foruser.settings["theme"])
@type location_result() :: {:ok, location_path()} | scxml_error()
Result type for location expression evaluation.
Returns:
{:ok, location_path()}- valid assignment pathscxml_error()- error if location is not assignable
@type position() :: {line :: pos_integer(), column :: pos_integer()}
A source position: 1-based line and column of the token that defines an AST node.
@type position_table() :: %{required(non_neg_integer()) => position()}
Maps a 0-based instruction index to the source position of the AST node that
emitted it. Produced by Predicator.Compiler.to_instructions_with_positions/2;
never part of the instruction list itself, so interchange and stored compiled
artifacts are unaffected.
The result of evaluating a predicate from public API functions.
Returns:
{:ok, value()}- successful evaluation with result value{:error, term()}- evaluation error with details
@type scxml_error() :: {:error, :undefined_variable, %{variable: binary()}} | {:error, :type_mismatch, %{expected: atom(), got: atom()}} | {:error, :invalid_location, %{expression: binary()}} | {:error, :evaluation_error, %{reason: binary()}} | {:error, :parse_error, %{message: binary(), line: integer(), column: integer()}}
SCXML-compatible error result for enhanced error handling.
Returns structured error information for SCXML datamodel compatibility:
{:error, :undefined_variable, %{variable: binary()}}- Variable not found in context{:error, :type_mismatch, %{expected: atom(), got: atom()}}- Type mismatch in operation{:error, :invalid_location, %{expression: binary()}}- Invalid assignment target{:error, :evaluation_error, %{reason: binary()}}- General evaluation error{:error, :parse_error, %{message: binary(), line: integer(), column: integer()}}- Parse error
@type scxml_result() :: {:ok, value()} | scxml_error()
SCXML-compatible result type for value expressions.
Returns:
{:ok, value()}- successful evaluation with result valuescxml_error()- structured error with SCXML-compatible details
@type value() :: boolean() | integer() | float() | binary() | list() | Date.t() | DateTime.t() | duration() | :undefined
A single value that can be used in predicates.
Values can be:
boolean()- true/false valuesinteger()- integer numeric valuesfloat()- floating-point numeric valuesbinary()- string valueslist()- lists of valuesDate.t()- date valuesDateTime.t()- datetime valuesduration()- duration values for time spans:undefined- represents undefined/null values; seePredicator.Undefinedfor the canonical definition of the sentinel
Functions
Checks if two values have matching types for operations.
Two values have matching types if they are both:
- integers
- booleans
- binaries (strings)
- lists
- maps (objects)
- dates
- datetimes
Examples
iex> Predicator.Types.types_match?(1, 2)
true
iex> Predicator.Types.types_match?("hello", "world")
true
iex> Predicator.Types.types_match?(%{a: 1}, %{b: 2})
true
iex> Predicator.Types.types_match?(1, "hello")
false
Checks if a value is undefined.
Delegates to Predicator.Undefined.undefined?/1 - see that module for the
canonical definition of the :undefined sentinel.
Examples
iex> Predicator.Types.undefined?(:undefined)
true
iex> Predicator.Types.undefined?(42)
false