YAML::PP::Grammar(3)
β¨ NAME β¨
okay bestie, this is YAML::PP::Grammar(3) from User Contributed Perl Documentation, and it is literally the YAML grammar. That's the whole vibe. We're in part 1 of 3, so stay with me π
πΈ GRAMMAR πΈ
okay so this is the Grammar in YAML. No cap, it's right here in all its glory β every key, callback, state transition and comment preserved exactly. Periodt.
# START OF YAML INLINE
# DO NOT CHANGE THIS
# This grammar is automatically generated from etc/grammar.yaml
---
NODETYPE_NODE:
DASH:
match: cb_seqstart
EOL: { new: FULLNODE }
WS: { new: FULLNODE }
DEFAULT: { new: NODETYPE_SCALAR_OR_MAP }
NODETYPE_SCALAR_OR_MAP:
# Flow nodes can follow tabs
WS: { new: FULLMAPVALUE_INLINE }
ALIAS:
match: cb_alias
EOL: { match: cb_send_alias_from_stack }
WS:
COLON:
match: cb_insert_map_alias
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
QUESTION:
match: cb_questionstart
EOL: { new: FULLNODE }
WS: { new: FULLNODE }
QUOTED:
match: cb_take_quoted
EOL: { match: cb_send_scalar }
WS:
COLON:
match: cb_insert_map
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
COLON:
match: cb_insert_map
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
QUOTED_MULTILINE:
match: cb_quoted_multiline
EOL: { }
PLAIN:
match: cb_start_plain
EOL:
match: cb_send_scalar
WS:
COLON:
match: cb_insert_map
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
COLON:
match: cb_insert_map
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
PLAIN_MULTI:
match: cb_send_plain_multi
EOL: { }
COLON:
match: cb_insert_empty_map
EOL: { new: FULLNODE }
WS: { new: FULLMAPVALUE_INLINE }
BLOCK_SCALAR:
match: cb_send_block_scalar
EOL: { }
FLOWSEQ_START:
match: cb_start_flowseq
new: NEWFLOWSEQ
FLOWMAP_START:
match: cb_start_flowmap
new: NEWFLOWMAP
DOC_END:
match: cb_end_document
EOL: { }
DOC_START:
match: cb_end_doc_start_document
EOL: { new: FULLNODE }
WS: { new: FULLNODE }
EOL:
new: NODETYPE_SCALAR_OR_MAP
NODETYPE_COMPLEX:
COLON:
match: cb_complexcolon
EOL: { new: FULLNODE }
WS: { new: FULLNODE }
DEFAULT:
match: cb_empty_complexvalue
new: NODETYPE_MAP
EOL:
new: NODETYPE_COMPLEX
RULE_FULLFLOWSCALAR:
ANCHOR:
match: cb_anchor
EOL: { new: RULE_FULLFLOWSCALAR_ANCHOR }
DEFAULT: { new: RULE_FULLFLOWSCALAR_ANCHOR }
TAG:
match: cb_tag
EOL: { new: RULE_FULLFLOWSCALAR_TAG }
DEFAULT: { new: RULE_FULLFLOWSCALAR_TAG }
DEFAULT: { new: RULE_FLOWSCALAR }
RULE_FULLFLOWSCALAR_ANCHOR:
WS: { new: RULE_FULLFLOWSCALAR_ANCHOR }
TAG:
match: cb_tag
WS: { new: RULE_FLOWSCALAR }
EOL: { new: RULE_FLOWSCALAR }
DEFAULT: { new: RULE_FLOWSCALAR }
RULE_FULLFLOWSCALAR_TAG:
WS: { new: RULE_FULLFLOWSCALAR_TAG }
ANCHOR:
match: cb_anchor
WS: { new: RULE_FLOWSCALAR }
EOL: { new: RULE_FLOWSCALAR }
DEFAULT: { new: RULE_FLOWSCALAR }
RULE_FLOWSCALAR:
FLOWSEQ_START: { match: cb_start_flowseq, new: NEWFLOWSEQ }
FLOWMAP_START: { match: cb_start_flowmap, new: NEWFLOWMAP }
ALIAS: { match: cb_send_alias, return: 1 }
QUOTED:
match: cb_take_quoted
EOL: { match: cb_send_scalar }
WS: { match: cb_send_scalar, return: 1 }
DEFAULT: { match: cb_send_scalar, return: 1 }
QUOTED_MULTILINE: { match: cb_quoted_multiline, return: 1 }
PLAIN:
match: cb_start_plain
EOL: { match: cb_send_scalar }
DEFAULT: { match: cb_send_scalar, return: 1 }
PLAIN_MULTI: { match: cb_send_plain_multi, return: 1 }
FLOW_COMMA: { match: cb_empty_flow_mapkey, return: 1 }
FLOWMAP_END:
match: cb_end_flowmap_empty
return: 1
FLOWSEQ:
FLOWSEQ_START: { match: cb_start_flowseq, new: NEWFLOWSEQ }
FLOWMAP_START: { match: cb_start_flowmap, new: NEWFLOWMAP }
ALIAS: { match: cb_send_flow_alias, new: FLOWSEQ_NEXT }
PLAIN:
match: cb_start_plain
EOL:
match: cb_send_scalar
new: FLOWSEQ_NEXT
DEFAULT:
new: FLOWSEQ_MAYBE_KEY
PLAIN_MULTI: { match: cb_send_plain_multi, new: FLOWSEQ_NEXT }
QUOTED:
match: cb_take_quoted
EOL:
match: cb_send_scalar
new: FLOWSEQ_NEXT
DEFAULT:
new: FLOWSEQ_MAYBE_KEY
QUOTED_MULTILINE: { match: cb_quoted_multiline, new: FLOWSEQ_NEXT }
COLON:
WS:
match: cb_insert_empty_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
EOL:
match: cb_insert_empty_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
FLOWSEQ_PROPS:
FLOWSEQ_START: { match: cb_start_flowseq, new: NEWFLOWSEQ }
FLOWMAP_START: { match: cb_start_flowmap, new: NEWFLOWMAP }
PLAIN:
match: cb_start_plain
EOL:
match: cb_send_scalar
new: FLOWSEQ_NEXT
DEFAULT:
new: FLOWSEQ_MAYBE_KEY
PLAIN_MULTI: { match: cb_send_plain_multi, new: FLOWSEQ_NEXT }
QUOTED:
match: cb_take_quoted
EOL:
match: cb_send_scalar
new: FLOWSEQ_NEXT
DEFAULT:
new: FLOWSEQ_MAYBE_KEY
QUOTED_MULTILINE: { match: cb_quoted_multiline, new: FLOWSEQ_NEXT }
FLOW_COMMA:
match: cb_empty_flowseq_comma
return: 1
FLOWSEQ_END:
match: cb_empty_flowseq_end
return: 1
COLON:
WS:
match: cb_insert_empty_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
EOL:
match: cb_insert_empty_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
FLOWSEQ_EMPTY:
FLOW_COMMA:
match: cb_empty_flowseq_comma
return: 1
FLOWSEQ_END:
match: cb_empty_flowseq_end
return: 1
FLOWSEQ_NEXT:
WS: { new: FLOWSEQ_NEXT }
EOL: { new: FLOWSEQ_NEXT }
FLOW_COMMA:
match: cb_flow_comma
return: 1
FLOWSEQ_END:
match: cb_end_flowseq
return: 1
FLOWSEQ_MAYBE_KEY:
WS: { new: FLOWSEQ_MAYBE_KEY }
COLON:
WS:
match: cb_insert_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
EOL:
match: cb_insert_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
DEFAULT:
match: cb_insert_implicit_flowseq_map
new: RULE_FULLFLOWSCALAR
DEFAULT:
new: FLOWSEQ_NEXT
FLOWMAP_CONTENT:
FLOWSEQ_START: { match: cb_start_flowseq, new: NEWFLOWSEQ }
FLOWMAP_START: { match: cb_start_flowmap, new: NEWFLOWMAP }
ALIAS: { match: cb_send_alias, return: 1 }
PLAIN: { match: cb_flowkey_plain, return: 1 }
PLAIN_MULTI: { match: cb_send_plain_multi, return: 1 }
QUOTED: { match: cb_flowkey_quoted, return: 1 }
QUOTED_MULTILINE: { match: cb_quoted_multiline, return: 1 }
COLON:
WS:
match: cb_empty_flow_mapkey
new: RULE_FULLFLOWSCALAR
EOL:
match: cb_empty_flow_mapkey
new: RULE_FULLFLOWSCALAR
FLOWMAP_PROPS:
FLOWSEQ_START: { match: cb_start_flowseq, new: NEWFLOWSEQ }
FLOWMAP_START: { match: cb_start_flowmap, new: NEWFLOWMAP }
PLAIN: { match: cb_flowkey_plain, return: 1 }
PLAIN_MULTI: { match: cb_send_plain_multi, return: 1 }
QUOTED: { match: cb_flowkey_quoted, return: 1 }
QUOTED_MULTILINE: { match: cb_quoted_multiline, return: 1 }
COLON:
WS:
match: cb_empty_flow_mapkey
new: RULE_FULLFLOWSCALAR
EOL:
match: cb_empty_flow_mapkey
new: RULE_FULLFLOWSCALAR
FLOW_COMMA:
match: cb_empty_flowmap_key_value
return: 1
FLOWMAP_END:
match: cb_end_empty_flowmap_key_value
return: 1
FLOWMAP_EMPTYKEY:
FLOW_COMMA:
match: cb_empty_flowmap_key_value
return: 1
FLOWMAP_END:
match: cb_end_empty_flowmap_key_value
return: 1
NEWFLOWSEQ:
EOL: { new: NEWFLOWSEQ }
WS: { new: NEWFLOWSEQ }
ANCHOR:
match: cb_anchor
WS: { new: NEWFLOWSEQ_ANCHOR_SPC }
EOL: { new: NEWFLOWSEQ_ANCHOR_SPC }
DEFAULT: { new: NEWFLOWSEQ_ANCHOR }
TAG:
match: cb_tag
WS: { new: NEWFLOWSEQ_TAG_SPC }
EOL: { new: NEWFLOWSEQ_TAG_SPC }
DEFAULT: { new: NEWFLOWSEQ_TAG }
FLOWSEQ_END:
match: cb_end_flowseq
return: 1
DEFAULT: { new: FLOWSEQ }
NODETYPE_FLOWSEQ:
EOL: { new: NODETYPE_FLOWSEQ }
WS: { new: NODETYPE_FLOWSEQ }
FLOWSEQ_END:
match: cb_end_flowseq
return: 1
DEFAULT: { new: NEWFLOWSEQ }
NODETYPE_FLOWMAPVALUE:
WS: { new: NODETYPE_FLOWMAPVALUE }
EOL: { new: NODETYPE_FLOWMAPVALUE }
COLON:
match: cb_flow_colon
WS: { new: RULE_FULLFLOWSCALAR }
EOL: { new: RULE_FULLFLOWSCALAR }
DEFAULT: { new: RULE_FULLFLOWSCALAR }
FLOW_COMMA:
match: cb_empty_flowmap_value
return: 1
FLOWMAP_END:
match: cb_end_flowmap_empty
return: 1
NEWFLOWSEQ_ANCHOR:
DEFAULT: { new: FLOWSEQ_EMPTY }
NEWFLOWSEQ_TAG:
DEFAULT: { new: FLOWSEQ_EMPTY }
π¦ NEWFLOWSEQ_ANCHOR_SPC
so you already grabbed an anchor inside a flow seq and now you're just chillin in whitespace waiting for something to happen. lived here tbh.
WSβ{ new: NEWFLOWSEQ_ANCHOR_SPC }EOLβ{ new: NEWFLOWSEQ_ANCHOR_SPC }TAGβ matchcb_tagWSβ{ new: FLOWSEQ_PROPS }EOLβ{ new: FLOWSEQ_PROPS }DEFAULTβ{ new: FLOWSEQ_EMPTY }
DEFAULTβ{ new: FLOWSEQ_PROPS }
π NEWFLOWSEQ_TAG_SPC
the tag twin of the state above π
same energy, but it's out here hunting for an ANCHOR instead.
WSβ{ new: NEWFLOWSEQ_TAG_SPC }EOLβ{ new: NEWFLOWSEQ_TAG_SPC }ANCHORβ matchcb_anchorWSβ{ new: FLOWSEQ_PROPS }EOLβ{ new: FLOWSEQ_PROPS }DEFAULTβ{ new: FLOWSEQ_EMPTY }
DEFAULTβ{ new: FLOWSEQ_PROPS }
π«Ά NEWFLOWMAP_ANCHOR
one singular line, she's low maintenance, she's iconic:
DEFAULTβ{ new: FLOWMAP_EMPTYKEY }
πΈ NEWFLOWMAP_TAG
same deal, tag flavoured:
DEFAULTβ{ new: FLOWMAP_EMPTYKEY }
β¨ NEWFLOWMAP_ANCHOR_SPC
whitespace era after an anchor in a flow map. notice how she can also catch a TAG on the way through π
WSβ{ new: NEWFLOWMAP_ANCHOR_SPC }EOLβ{ new: NEWFLOWMAP_ANCHOR_SPC }TAGβ matchcb_tagWSβ{ new: FLOWMAP_PROPS }EOLβ{ new: FLOWMAP_PROPS }DEFAULTβ{ new: FLOWMAP_EMPTYKEY }
DEFAULTβ{ new: FLOWMAP_PROPS }
π NEWFLOWMAP_TAG_SPC
and the mirror image, where the ANCHOR can still slide in:
WSβ{ new: NEWFLOWMAP_TAG_SPC }EOLβ{ new: NEWFLOWMAP_TAG_SPC }ANCHORβ matchcb_anchorWSβ{ new: FLOWMAP_PROPS }EOLβ{ new: FLOWMAP_PROPS }DEFAULTβ{ new: FLOWMAP_EMPTYKEY }
DEFAULTβ{ new: FLOWMAP_PROPS }
π NEWFLOWMAP
the moment you see a ? it's giving explicit key energy and we hop to FLOWMAP_EXPLICIT_KEY. everything else? vibes, we stay put.
EOLβ{ new: NEWFLOWMAP }WSβ{ new: NEWFLOWMAP }QUESTIONβ{ match: cb_flow_question, new: FLOWMAP_EXPLICIT_KEY }DEFAULTβ{ new: FLOWMAP }
π FLOWMAP_EXPLICIT_KEY
the explicit key state, and bestie you can leave it two ways β a FLOWMAP_END or a FLOW_COMMA. and yes, those are two different callbacks, don't confuse them:
WSβ{ new: FLOWMAP_EXPLICIT_KEY }EOLβ{ new: FLOWMAP_EXPLICIT_KEY }FLOWMAP_ENDβ matchcb_end_empty_flowmap_key_value, thenreturn: 1FLOW_COMMAβ matchcb_empty_flowmap_key_value, thenreturn: 1DEFAULTβ{ new: FLOWMAP }
fr fr look at those two match names again.cb_end_empty_flowmap_key_valuevscb_empty_flowmap_key_value. one letter of a difference. π« not me almost typing them as one.
π§ FLOWMAP
the main character of flow maps β¨ properties, ends, empty keys β she does it all.
EOLβ{ new: FLOWMAP }WSβ{ new: FLOWMAP }ANCHORβ matchcb_anchorWSβ{ new: NEWFLOWMAP_ANCHOR_SPC }EOLβ{ new: NEWFLOWMAP_ANCHOR_SPC }DEFAULTβ{ new: NEWFLOWMAP_ANCHOR }
TAGβ matchcb_tagWSβ{ new: NEWFLOWMAP_TAG_SPC }EOLβ{ new: NEWFLOWMAP_TAG_SPC }DEFAULTβ{ new: NEWFLOWMAP_TAG }
FLOWMAP_ENDβ matchcb_end_flowmap, thenreturn: 1COLONWS- match
cb_empty_flow_mapkey - new
RULE_FULLFLOWSCALAR
- match
EOL- match
cb_empty_flow_mapkey - new
RULE_FULLFLOWSCALAR
- match
DEFAULTβ{ new: FLOWMAP_CONTENT }
π NODETYPE_FLOWMAP
once the node type is settled as a flow map, a comma means fresh start (NEWFLOWMAP) and an end means we're done out here.
EOLβ{ new: NODETYPE_FLOWMAP }WSβ{ new: NODETYPE_FLOWMAP }FLOWMAP_ENDβ matchcb_end_flowmap, thenreturn: 1FLOW_COMMAβ{ match: cb_flow_comma, new: NEWFLOWMAP }DEFAULTβ{ new: NEWFLOWMAP }
π END_FLOW
tiny but mighty. one job:
EOLβ matchcb_end_outer_flow, thenreturn: 1
π₯ RULE_MAPKEY
the big one. this is the rule that figures out what kind of key you're dealing with, and every branch has opinions.
QUESTIONβ matchcb_questionEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
ALIASβ matchcb_send_alias_keyWSCOLONEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
QUOTEDβ matchcb_take_quoted_keyWSCOLONEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
COLONEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
PLAINβ matchcb_mapkeyWSCOLONβ matchcb_send_mapkeyEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
COLONβ matchcb_send_mapkeyEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
COLONβ matchcb_empty_mapkeyEOLβ{ new: FULLNODE }WSβ{ new: FULLMAPVALUE_INLINE }
DOC_ENDβ matchcb_end_documentEOLβ{ }
DOC_STARTβ matchcb_end_doc_start_documentEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
EOLβ{ new: RULE_MAPKEY }
π«Ά noticeALIASonly has theWSβCOLONpath and no top-levelCOLON, andQUOTEDhas both. that asymmetry is on purpose, don't go "fixing" it.
π¦ NODETYPE_SEQ
seq mode. a dash means new item, and we're bouncing into a full node for the value.
DASHβ matchcb_seqitemEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
DOC_ENDβ matchcb_end_documentEOLβ{ }
DOC_STARTβ matchcb_end_doc_start_documentEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
EOLβ{ new: NODETYPE_SEQ }
π NODETYPE_MAP
map mode, and look at her β she's cool with ANCHOR then TAG, TAG then ANCHOR, or neither. flexible queen.
ANCHORβ matchcb_anchorWSTAGβ matchcb_tagWSβ{ new: RULE_MAPKEY }
DEFAULTβ{ new: RULE_MAPKEY }
TAGβ matchcb_tagWSANCHORβ matchcb_anchorWSβ{ new: RULE_MAPKEY }
DEFAULTβ{ new: RULE_MAPKEY }
DEFAULTβ{ new: RULE_MAPKEY }
πΈ FULLNODE_ANCHOR
you've got an anchor, now you're assembling the rest of the node. tags, eols, and the eventual NODETYPE_NODE.
TAGβ matchcb_tagEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSANCHORβ matchcb_anchorWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
ANCHORβ matchcb_anchorWSTAGβ matchcb_tagWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
EOLβ{ new: FULLNODE_ANCHOR }DEFAULTβ{ new: NODETYPE_NODE }
β FULLNODE_TAG
tag first this time. and yeah, that DEFAULT line has a lil trailing comma in it β { new: NODETYPE_SCALAR_OR_MAP, } β she's got baggage, we keep her exactly as she is π
ANCHORβ matchcb_anchorEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSTAGβ matchcb_tagWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP, }
TAGβ matchcb_tagWSANCHORβ matchcb_anchorWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
EOLβ{ new: FULLNODE_TAG }DEFAULTβ{ new: NODETYPE_NODE }
π FULLNODE_TAG_ANCHOR
both properties already handled, so EOL just loops back to herself and everything else becomes a node.
ANCHORβ matchcb_anchorWSTAGβ matchcb_tagWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
TAGβ matchcb_tagWSANCHORβ matchcb_anchorWSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
EOLβ{ new: FULLNODE_TAG_ANCHOR }DEFAULTβ{ new: NODETYPE_NODE }
π₯ FULLNODE
the fully loaded version, where cb_property_eol can fire at every turn and cart you off to one of the property states π
ANCHORβ matchcb_anchorEOLβ{ match: cb_property_eol, new: FULLNODE_ANCHOR }WSTAGβ matchcb_tagEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
TAGβ matchcb_tagEOLβ{ match: cb_property_eol, new: FULLNODE_TAG }WSANCHORβ matchcb_anchorEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSβ{ new: NODETYPE_SCALAR_OR_MAP }
DEFAULTβ{ new: NODETYPE_SCALAR_OR_MAP }
EOLβ{ new: FULLNODE }DEFAULTβ{ new: NODETYPE_NODE }
π FULLMAPVALUE_INLINE
a map value that lives on the same line. properties get checked, then it's NODETYPE_MAPVALUE_INLINE time.
ANCHORβ matchcb_anchorEOLβ{ match: cb_property_eol, new: FULLNODE_ANCHOR }WSTAGβ matchcb_tagEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSβ{ new: NODETYPE_MAPVALUE_INLINE }
DEFAULTβ{ new: NODETYPE_MAPVALUE_INLINE }
TAGβ matchcb_tagEOLβ{ match: cb_property_eol, new: FULLNODE_TAG }WSANCHORβ matchcb_anchorEOLβ{ match: cb_property_eol, new: FULLNODE_TAG_ANCHOR }WSβ{ new: NODETYPE_MAPVALUE_INLINE }
DEFAULTβ{ new: NODETYPE_MAPVALUE_INLINE }
DEFAULTβ{ new: NODETYPE_MAPVALUE_INLINE }
π NODETYPE_MAPVALUE_INLINE
the actual dispatch board for inline map values. every scalar flavour gets a callback, and flow collections get started up π¬
ALIASβ matchcb_send_aliasEOLβ{ }
QUOTEDβ matchcb_take_quotedEOLβ{ match: cb_send_scalar }
QUOTED_MULTILINEβ matchcb_quoted_multilineEOLβ{ }
PLAINβ matchcb_start_plainEOLβ matchcb_send_scalar
PLAIN_MULTIβ matchcb_send_plain_multiEOLβ{ }
BLOCK_SCALARβ matchcb_send_block_scalarEOLβ{ }
FLOWSEQ_STARTβ matchcb_start_flowseq- new
NEWFLOWSEQ
- new
FLOWMAP_STARTβ matchcb_start_flowmap- new
NEWFLOWMAP
- new
DOC_ENDβ matchcb_end_documentEOLβ{ }
π§ note thatFLOWSEQ_STARTandFLOWMAP_STARTare the only two here written with a barenew:line instead of{ new: ... }. that's how the source has them, no cap. don't normalise it.
π DOCUMENT_END
we're past the document, but a new DOC_START still means a fresh FULLNODE.
DOC_ENDβ matchcb_end_documentEOLβ{ }
DOC_STARTβ matchcb_end_doc_start_documentEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
EOLβ{ new: DOCUMENT_END }
π
STREAM
the top of the whole thing β¨ directives, explicit doc starts, implicit doc starts, empty doc ends β she's seen it all.
DOC_ENDβ matchcb_end_document_emptyEOLβ{ }
DOC_STARTβ matchcb_doc_start_explicitEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
YAML_DIRECTIVEβ matchcb_set_yaml_version_directiveEOLβ{ new: DIRECTIVE }WSβ{ new: DIRECTIVE }
RESERVED_DIRECTIVEβ matchcb_reserved_directiveEOLβ{ new: DIRECTIVE }WSβ{ new: DIRECTIVE }
TAG_DIRECTIVEβ matchcb_tag_directiveEOLβ{ new: DIRECTIVE }WSβ{ new: DIRECTIVE }
EOLβ{ new: STREAM }DEFAULTβ matchcb_doc_start_implicit- new
FULLNODE
- new
π§ DIRECTIVE
after a directive, an explicit document start is the move π¬
DOC_STARTβ matchcb_doc_start_explicitEOLβ{ new: FULLNODE }WSβ{ new: FULLNODE }
...and we're back in the state table π last stretch, bestie, I promise.
YAML_DIRECTIVE:
match: cb_set_yaml_version_directive
EOL: { new: DIRECTIVE }
WS: { new: DIRECTIVE }
RESERVED_DIRECTIVE:
match: cb_reserved_directive
EOL: { new: DIRECTIVE }
WS: { new: DIRECTIVE }
TAG_DIRECTIVE:
match: cb_tag_directive
EOL: { new: DIRECTIVE }
WS: { new: DIRECTIVE }
EOL:
new: DIRECTIVE
# END OF YAML INLINE
Okay so look at these last three states and notice the pattern, because it's so clean πβ¨ each directive state does the exact same trio of things:
- it
matches on its own callback βcb_set_yaml_version_directiveforYAML_DIRECTIVE,cb_reserved_directiveforRESERVED_DIRECTIVE, andcb_tag_directiveforTAG_DIRECTIVE - on
EOLit goes to theDIRECTIVEstate via{ new: DIRECTIVE }π« - on
WSβ same thing,{ new: DIRECTIVE }π«Ά
so both a newline and whitespace bounce you into DIRECTIVE. no cap, that's the whole vibe of these three. they're literally triplets π
And then the very last state, EOL, just does new: DIRECTIVE. that's it. that's her whole job π
Then that final comment line, # END OF YAML INLINE, and the inline-grammar chunk of the page is done β we ate and left no crumbs π
for real though, heads up: if you're editing or extending this, keep every state name and callback name exactly as written, because this is a state machine and it does not do vibes-based matching π
and that's a wrap on the grammar, bestie π¦π this page is YAML::PP::Grammar(3), part of the User Contributed Perl Documentation, and it rides along with perl v5.42.0, dated 2026-04-24 β so if you're reading this, that's your version and date right there, no scrolling required πβ¨ go forth and parse some YAML, ily, bye ππ
π¦ where this page comes from
- opensuse-leap 16.0: perl-YAML-PP 0.40.0-bp160.1.1 Β· Artistic-1.0 OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms