Predicator.Types (predicator v3.3.0)

View Source

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.

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.

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.

Functions

Checks if two values have matching types for operations.

Checks if a value is undefined.

Types

context()

@type context() :: %{required(binary() | atom()) => value()}

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"}

evaluator_state()

@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 execute
  • instruction_pointer - current position in instruction list
  • stack - evaluation stack (top element is head of list)
  • context - variable bindings
  • halted - whether execution has stopped

instruction()

@type instruction() :: [binary() | value()]

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
  • ["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
  • ["call", binary(), integer()] - Call built-in function with arguments from stack

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
["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
["call", "len", 1]    # Pop 1 argument, call len function, push result

instruction_list()

@type instruction_list() :: [instruction()]

A list of instructions that form a complete program.

Instructions are executed in order by the stack machine.

internal_result()

@type internal_result() :: value() | {:error, term()}

The internal result of evaluating a predicate from Evaluator functions.

Returns:

  • value() - the final evaluation result value
  • {:error, term()} - evaluation error with details

location_path()

@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"] (for user.settings["theme"])

location_result()

@type location_result() :: {:ok, location_path()} | scxml_error()

Result type for location expression evaluation.

Returns:

  • {:ok, location_path()} - valid assignment path
  • scxml_error() - error if location is not assignable

result()

@type result() :: {:ok, value()} | {:error, term()}

The result of evaluating a predicate from public API functions.

Returns:

  • {:ok, value()} - successful evaluation with result value
  • {:error, term()} - evaluation error with details

scxml_error()

@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

scxml_result()

@type scxml_result() :: {:ok, value()} | scxml_error()

SCXML-compatible result type for value expressions.

Returns:

  • {:ok, value()} - successful evaluation with result value
  • scxml_error() - structured error with SCXML-compatible details

value()

@type value() ::
  boolean()
  | integer()
  | float()
  | binary()
  | list()
  | Date.t()
  | DateTime.t()
  | :undefined

A single value that can be used in predicates.

Values can be:

  • boolean() - true/false values
  • integer() - integer numeric values
  • float() - floating-point numeric values
  • binary() - string values
  • list() - lists of values
  • Date.t() - date values
  • DateTime.t() - datetime values
  • :undefined - represents undefined/null values

Functions

types_match?(a, b)

@spec types_match?(value(), value()) :: boolean()

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

undefined?(value)

@spec undefined?(value()) :: boolean()

Checks if a value is undefined.

Examples

iex> Predicator.Types.undefined?(:undefined)
true

iex> Predicator.Types.undefined?(42)
false