-
-
Save disarticulate/9e42e35885aec2a04e372db5a702e9ec to your computer and use it in GitHub Desktop.
"Offside rule" indentation parsing with PEG.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Parse a document using "offside rule" indentation (as in Python) into lines | |
// grouped by indentation level, using PEG.js. | |
// Attempts to segregate the "stateful" rules from the other production/parsing | |
// rules by "disallowing" indentation-level-sensitive rules from consuming any | |
// text. | |
{ var margin_stack = [""]; } | |
Document | |
= content: Element+ | |
BlankLine* | |
{ return content; } | |
Element | |
= BlankLine* | |
content: (CurrentBlockElement / IndentedBlock) | |
{ return content; } | |
CurrentBlockElement | |
= &MAINTAIN_MARGIN content:Line | |
{ return content; } | |
IndentedBlock | |
= &INCREASE_MARGIN | |
first: CurrentBlockElement | |
content: Element* | |
&DECREASE_MARGIN | |
{ return [first].concat(content); } | |
Line | |
= BlankSpace? | |
content: $(!LineEnding .)+ LineEnding | |
{ return content; } | |
INCREASE_MARGIN | |
= indent: $BlankSpace? | |
&{ return (indent !== margin_stack[0]) | |
&& indent.startsWith(margin_stack[0]); } | |
{ margin_stack.unshift(indent); } | |
MAINTAIN_MARGIN | |
= indent: $BlankSpace? | |
&{ return indent === margin_stack[0]; } | |
DECREASE_MARGIN | |
= EOF | |
/ indent: $BlankSpace? | |
&{ return margin_stack.slice(1).includes(indent); } | |
{ margin_stack.shift(); } | |
BlankLine | |
= BlankSpace? EOL | |
/ BlankSpace EOF | |
LineEnding | |
= BlankSpace? (EOL / EOF) | |
BlankSpace | |
= [ \t]+ | |
EOL = "\r\n" / "\n" / "\r" | |
EOF = !. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment