Predicator.ContextLocation (predicator v3.5.0)

View Source

Resolves location paths for assignment operations in SCXML datamodel expressions.

This module takes parsed AST nodes and extracts location paths that can be used for assignment operations. It validates that expressions represent assignable locations (l-values) rather than computed values.

Location Path Format

Location paths are returned as lists of keys/indices that represent the path to a specific location in the context data structure:

  • ["user"] - top-level variable user
  • ["user", "name"] - property access user.name
  • ["items", 0] - array access items[0]
  • ["user", "profile", "settings", "theme"] - nested access user.profile.settings.theme

Assignable vs Non-Assignable

Assignable (valid locations):

  • Simple identifiers: user
  • Property access: user.name, obj.prop
  • Bracket access: items[0], obj["key"]
  • Mixed notation: user.items[0].name, data["users"][0]["profile"]

Non-Assignable (invalid locations):

  • Literals: 42, "string", true
  • Function calls: len(items), upper(name)
  • Arithmetic expressions: user.age + 1, items[i + 1]
  • Any computed values that can't be used as assignment targets

Examples

iex> alias Predicator.{ContextLocation, Lexer, Parser}
iex> {:ok, tokens} = Lexer.tokenize("user.name")
iex> {:ok, ast} = Parser.parse(tokens)
iex> ContextLocation.resolve(ast, %{"user" => %{"name" => "John"}})
{:ok, ["user", "name"]}

iex> {:ok, tokens} = Lexer.tokenize("items[0]")
iex> {:ok, ast} = Parser.parse(tokens)
iex> ContextLocation.resolve(ast, %{"items" => [1, 2, 3]})
{:ok, ["items", 0]}

Summary

Types

A location path representing the sequence of keys/indices to reach a location in the context.

Result of resolving a location expression.

Functions

Resolves an AST node to a location path for assignment operations.

Types

location_path()

@type location_path() :: [binary() | integer()]

A location path representing the sequence of keys/indices to reach a location in the context.

String keys represent object properties, integer keys represent array indices.

location_result()

@type location_result() ::
  {:ok, location_path()} | {:error, Predicator.Errors.LocationError.t()}

Result of resolving a location expression.

Returns either a successful path or a structured error explaining why the location is invalid.

Functions

resolve(ast_node, context)

@spec resolve(term(), Predicator.Types.context()) :: location_result()

Resolves an AST node to a location path for assignment operations.

Takes a parsed AST node and attempts to extract a valid location path. Validates that the expression represents an assignable location.

Parameters

  • ast_node - The parsed AST node to resolve
  • context - The evaluation context (used for validating array bounds, etc.)

Returns

  • {:ok, path} - A valid location path
  • {:error, %LocationError{}} - An error explaining why the location is invalid

Examples

# Simple identifier
resolve({:identifier, "user"}, %{})
#=> {:ok, ["user"]}

# Property access
resolve({:property_access, {:identifier, "user"}, "name"}, %{})
#=> {:ok, ["user", "name"]}

# Bracket access
resolve({:bracket_access, {:identifier, "items"}, {:literal, 0}}, %{})
#=> {:ok, ["items", 0]}

# Invalid: literal value
resolve({:literal, 42}, %{})
#=> {:error, %LocationError{type: :not_assignable, message: "Cannot assign to literal value"}}