Parser
in package
Hand-written recursive-descent `.dxn` parser -- the reverse of {@see Printer}, built directly on {@see Lexer}'s token stream.
A struct decodes against a compiled schema when $registry has
one for that name (Validator::materialize(), same as the
binary decoder); with no registry, or no schema registered for that
name, it decodes to an opaque DXNStruct. Same story for a
non-built-in tag against the registry's own tag table -- falls back
to DXNCustomTag -- never a hard failure, matching
dxn/DXN.md ยง1.4's "opaque tagged value, not an error" contract.
Table of Contents
Constants
- BUILT_IN_TAGS : mixed = ['ordered' => true, 'sorted-set' => true, 'arra...
Properties
Methods
- parse() : mixed
- __construct() : mixed
- advance() : Token
- advanceAnd() : mixed
- Advances past the current token (already matched by the caller) and returns `$value` -- for literals with no token property worth extracting.
- at() : bool
- Reads `$this->pos`, mutable parser state -- PHPStan otherwise assumes a "pure" method called twice with the same argument returns the same result both times, which doesn't hold here once something between the two calls (typically `next()`) advances the cursor.
- buildMap() : array<int|string, mixed>
- dispatchTag() : mixed
- flagsStringToArray() : array<string, bool>
- isDiscard() : bool
- materializeStruct() : mixed
- next() : Token
- parseArrayTag() : array<int, mixed>
- parseAt() : mixed
- `@{...}` (set), or `@identifier value` (tag_form). Discard is already stripped in {@see self::parseValue()}.
- parseBracketedItems() : array<int, mixed>
- parseBytesTag() : DXNBytes
- parseCharToken() : DXNChar
- parseDocument() : mixed
- Top-level entry: optional header, then exactly one value.
- parseEntries() : array<int, array{0: mixed, 1: mixed}>
- `{map_entry*}`, ordered pairs -- used by both `map_lit` and `struct_keyed`. The colon-shorthand key (`MAP_KEY` token) is keyword-typed per the grammar (`name: value` and `:name => value` are the exact same value), so it's wrapped as {@see DXNKeyword} here just like an explicit `:name` would be -- callers (map vs struct) each reduce that down to whatever shape they actually need.
- parseFloatToken() : float
- parseKeywordToken() : DXNKeyword
- parseList() : DXNList
- parseOrderedTag() : DXNOrderedMap
- parsePercent() : mixed
- `%{...}` (map) or `%Name{...}`/`%Name[...]` (struct).
- parseRationalToken() : DXNRational
- parseRegexToken() : DXNRegex
- parseSet() : DXNSet
- parseSortedSetTag() : DXNSortedSet
- parseStringValue() : string
- parseTuple() : DXNTuple
- parseValue() : mixed
- `value = {skip}, value_body` -- `skip` here is only ever a discard; comments never reach the token stream.
- parseValueBody() : mixed
- peek() : Token
- skipDiscards() : void
- structFieldName() : string
- tryConsumeHeader() : void
Constants
BUILT_IN_TAGS
private
mixed
BUILT_IN_TAGS
= ['ordered' => true, 'sorted-set' => true, 'array' => true, 'uuid' => true, 'uri' => true, 'bytes' => true, 'datetime' => true, 'duration' => true]
Properties
$pos
private
int
$pos
= 0
$registry
private
Registry|null
$registry
$tokens read-only
private
array<int, Token>
$tokens
Methods
parse()
public
static parse(string $text[, Registry|null $registry = null ]) : mixed
Parameters
- $text : string
- $registry : Registry|null = null
__construct()
private
__construct(array<int, Token> $tokens, Registry|null $registry) : mixed
Parameters
advance()
private
advance() : Token
Return values
TokenadvanceAnd()
Advances past the current token (already matched by the caller) and returns `$value` -- for literals with no token property worth extracting.
private
advanceAnd(mixed $value) : mixed
Parameters
- $value : mixed
at()
Reads `$this->pos`, mutable parser state -- PHPStan otherwise assumes a "pure" method called twice with the same argument returns the same result both times, which doesn't hold here once something between the two calls (typically `next()`) advances the cursor.
private
at(string $type) : bool
Parameters
- $type : string
Tags
Return values
boolbuildMap()
private
buildMap(array<int, array{0: mixed, 1: mixed}> $pairs) : array<int|string, mixed>
Parameters
- $pairs : array<int, array{0: mixed, 1: mixed}>
Return values
array<int|string, mixed>dispatchTag()
private
dispatchTag(string $name, int $offset) : mixed
Parameters
- $name : string
- $offset : int
flagsStringToArray()
private
static flagsStringToArray(string $flags) : array<string, bool>
Parameters
- $flags : string
Return values
array<string, bool>isDiscard()
private
isDiscard() : bool
Return values
boolmaterializeStruct()
private
materializeStruct(string $name, DXNStruct $struct) : mixed
Parameters
- $name : string
- $struct : DXNStruct
next()
private
next(string $type) : Token
Parameters
- $type : string
Return values
TokenparseArrayTag()
private
parseArrayTag(int $offset) : array<int, mixed>
Parameters
- $offset : int
Return values
array<int, mixed>parseAt()
`@{...}` (set), or `@identifier value` (tag_form). Discard is already stripped in {@see self::parseValue()}.
private
parseAt() : mixed
parseBracketedItems()
private
parseBracketedItems(string $open, string $close) : array<int, mixed>
Parameters
- $open : string
- $close : string
Return values
array<int, mixed>parseBytesTag()
private
parseBytesTag(string $name, int $offset) : DXNBytes
Parameters
- $name : string
- $offset : int
Return values
DXNBytesparseCharToken()
private
parseCharToken() : DXNChar
Return values
DXNCharparseDocument()
Top-level entry: optional header, then exactly one value.
private
parseDocument() : mixed
parseEntries()
`{map_entry*}`, ordered pairs -- used by both `map_lit` and `struct_keyed`. The colon-shorthand key (`MAP_KEY` token) is keyword-typed per the grammar (`name: value` and `:name => value` are the exact same value), so it's wrapped as {@see DXNKeyword} here just like an explicit `:name` would be -- callers (map vs struct) each reduce that down to whatever shape they actually need.
private
parseEntries() : array<int, array{0: mixed, 1: mixed}>
Return values
array<int, array{0: mixed, 1: mixed}>parseFloatToken()
private
parseFloatToken(string $text) : float
Parameters
- $text : string
Return values
floatparseKeywordToken()
private
parseKeywordToken() : DXNKeyword
Return values
DXNKeywordparseList()
private
parseList() : DXNList
Return values
DXNListparseOrderedTag()
private
parseOrderedTag(int $offset) : DXNOrderedMap
Parameters
- $offset : int
Return values
DXNOrderedMapparsePercent()
`%{...}` (map) or `%Name{...}`/`%Name[...]` (struct).
private
parsePercent() : mixed
parseRationalToken()
private
parseRationalToken(string $text) : DXNRational
Parameters
- $text : string
Return values
DXNRationalparseRegexToken()
private
parseRegexToken() : DXNRegex
Return values
DXNRegexparseSet()
private
parseSet() : DXNSet
Return values
DXNSetparseSortedSetTag()
private
parseSortedSetTag(int $offset) : DXNSortedSet
Parameters
- $offset : int
Return values
DXNSortedSetparseStringValue()
private
parseStringValue(string $tagName, int $offset) : string
Parameters
- $tagName : string
- $offset : int
Return values
stringparseTuple()
private
parseTuple() : DXNTuple
Return values
DXNTupleparseValue()
`value = {skip}, value_body` -- `skip` here is only ever a discard; comments never reach the token stream.
private
parseValue() : mixed
parseValueBody()
private
parseValueBody() : mixed
peek()
private
peek() : Token
Return values
TokenskipDiscards()
private
skipDiscards() : void
structFieldName()
private
structFieldName(mixed $key) : string
Parameters
- $key : mixed
Return values
stringtryConsumeHeader()
private
tryConsumeHeader() : void