Parser
in package
CRUDUI expression parser: Token[] -> AST (expressions.md §3/§4, JS Parser parity).
Recursive-descent grammar (EBNF, lowest precedence first):
ternary = or [ "?" ternary ":" ternary ] (right-associative) or = and { "||" and } and = not { "&&" not } not = "!" not | comparison comparison = primary [ cmp_op cmp_value | in_op value_list ] primary = "(" or ")" | path | literal path = [ "." | ".." ] identifier { "." (identifier | number | "*") }
Operator precedence and ternary right-associativity come from the grammar productions, not a heuristic. No eval, no split (GRAMMAR §10).
Table of Contents
Constants
- MAX_EXPRESSION_DEPTH : mixed = 64
- The most nodes on a path from the root of an expression's syntax tree to a leaf. A deeper expression is a parse error in every runtime.
Properties
- $current : int
- $height : int
- Height of the node the last parse method returned.
- $open : int
- Nodes whose children are being parsed: each is an ancestor of what comes next.
- $tokens : array<string|int, mixed>
Methods
- __construct() : mixed
- Build a parser over a lexer's token stream (must end in EOF).
- parse() : Node
- Parse the full token stream into one AST root. Throws on trailing tokens.
- advance() : Token
- check() : bool
- enter() : void
- Open a node whose children follow; the tree is at least one level deeper than the open nodes.
- isAtEnd() : bool
- literal() : LiteralNode|null
- Consume a token of `$type` as a literal of `$valueType`, or leave the input and return null.
- match() : bool
- node() : int
- Record a node whose tallest child has $childHeight as the last parsed node; returns its height.
- parseAndExpression() : Node
- parseComparison() : Node
- parseComparisonValue() : Node
- Right-hand side of a comparison. An unquoted identifier with NO following dot is a string literal (`.country == US` → 'US'); an identifier followed by a dot is a path reference, so backtrack and parse it as a path.
- parseNotExpression() : Node
- parseOrExpression() : Node
- parsePath() : PathNode
- parsePrimary() : Node
- parseTernaryExpression() : Node
- parseValueList() : array<int, Node>
- parseValueListItem() : Node
- peek() : Token
- previous() : Token
- tooDeep() : ParseError
Constants
MAX_EXPRESSION_DEPTH
The most nodes on a path from the root of an expression's syntax tree to a leaf. A deeper expression is a parse error in every runtime.
public
mixed
MAX_EXPRESSION_DEPTH
= 64
Properties
$current
private
int
$current
= 0
$height
Height of the node the last parse method returned.
private
int
$height
= 0
$open
Nodes whose children are being parsed: each is an ancestor of what comes next.
private
int
$open
= 0
$tokens read-only
private
array<string|int, mixed>
$tokens
Methods
__construct()
Build a parser over a lexer's token stream (must end in EOF).
public
__construct(array<int, Token> $tokens) : mixed
Parameters
- $tokens : array<int, Token>
parse()
Parse the full token stream into one AST root. Throws on trailing tokens.
public
parse() : Node
Return values
Nodeadvance()
private
advance() : Token
Return values
Tokencheck()
private
check(TokenType $type) : bool
Parameters
- $type : TokenType
Return values
boolenter()
Open a node whose children follow; the tree is at least one level deeper than the open nodes.
private
enter() : void
isAtEnd()
private
isAtEnd() : bool
Return values
boolliteral()
Consume a token of `$type` as a literal of `$valueType`, or leave the input and return null.
private
literal(TokenType $type, string $valueType) : LiteralNode|null
Parameters
- $type : TokenType
- $valueType : string
Return values
LiteralNode|nullmatch()
private
match(TokenType ...$types) : bool
Parameters
- $types : TokenType
Return values
boolnode()
Record a node whose tallest child has $childHeight as the last parsed node; returns its height.
private
node(int $childHeight) : int
Parameters
- $childHeight : int
Return values
intparseAndExpression()
private
parseAndExpression() : Node
Return values
NodeparseComparison()
private
parseComparison() : Node
Return values
NodeparseComparisonValue()
Right-hand side of a comparison. An unquoted identifier with NO following dot is a string literal (`.country == US` → 'US'); an identifier followed by a dot is a path reference, so backtrack and parse it as a path.
private
parseComparisonValue() : Node
Return values
NodeparseNotExpression()
private
parseNotExpression() : Node
Return values
NodeparseOrExpression()
private
parseOrExpression() : Node
Return values
NodeparsePath()
private
parsePath() : PathNode
Return values
PathNodeparsePrimary()
private
parsePrimary() : Node
Return values
NodeparseTernaryExpression()
private
parseTernaryExpression() : Node
Return values
NodeparseValueList()
private
parseValueList() : array<int, Node>
Return values
array<int, Node>parseValueListItem()
private
parseValueListItem() : Node
Return values
Nodepeek()
private
peek() : Token
Return values
Tokenprevious()
private
previous() : Token
Return values
TokentooDeep()
private
static tooDeep() : ParseError