Skip to content

Instantly share code, notes, and snippets.

@disarticulate
Forked from biogeo/indentation.pegjs
Created April 23, 2017 21:28
Show Gist options
  • Save disarticulate/9e42e35885aec2a04e372db5a702e9ec to your computer and use it in GitHub Desktop.
Save disarticulate/9e42e35885aec2a04e372db5a702e9ec to your computer and use it in GitHub Desktop.
"Offside rule" indentation parsing with PEG.js
// 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