require ‘rattler/compiler’
grammar Rattler::Compiler::Metagrammar
include Rattler::Parsers
%whitespace (SPACE+ / comment)*
grammar <- heading rules EOF <Grammar>
heading <- requires module_decl? includes start_directive? { heading *_ }
requires <- require_statement* { { :requires => _ } }
require_statement <- ~‘require` @(!eol .)+ ~eol
/ ~`require_relative` @(!eol .)+ ~eol { expand_relative _ }
module_decl <- ~‘parser` constant (~’<‘ constant)? ~eol { parser_decl *_ }
/ ~`grammar` constant ~eol { { :grammar_name => _ } }
includes <- (~‘include` constant ~eol)* { { :includes => _ } }
start_directive <- ~‘%start` identifier { { :start_rule => _ } }
rules <- (directive / rule / block_close)* <RuleSet>
directive <- ws_directive / wc_directive / inline_directive / fragments
ws_directive <- ws_decl ~‘{’ { start_ws _ }
/ ws_decl { set_ws _ }
ws_decl <- ~‘%whitespace` unattributed
wc_directive <- wc_decl ~‘{’ { start_wc _ }
/ wc_decl { set_wc _ }
wc_decl <- ~‘%word_character` unattributed
inline_directive <- ~‘%inline` ~’{‘ { start_inline }
/ ~`%inline` { set_inline }
fragments <- ~‘%fragments` ~’{‘ { start_fragments }
/ ~`%fragments` { set_fragments }
block_close <- ~‘}’ { end_block }
rule <- identifier ~‘<-’ expression { rule *_ }
unattributed <- unattributed ~‘/’ terms <Choice>
/ terms
expression <- expression ~‘/’ attributed <Choice>
/ attributed
attributed <- attributed? (semantic_action / node_action) <AttributedSequence>
/ attributed_terms
old_node_action <- @(name (~‘.’ var_name)?)
semantic_action <- ~‘{’ action_code ~‘}’ <SemanticAction>
action_code <- @(( ‘{’ [^}]* ‘}’
/ [^{}] )*)
node_action <- ~‘<’ (name (~‘.’ var_name)?)? literal? ~‘>’ <NodeAction>
attributed_terms <- attributed term <Sequence>
/ terms
terms <- terms term <Sequence>
/ term
term <- fail_expr / labeled / labelable
fail_expr <- fail_keyword fail_arg <Fail>
labeled <- var_name ~‘:’ labelable <Label>
labelable <- semantic_term / list / list_term
semantic_term <- ~‘^’ semantic_action
/ ~'&' semantic_action { Assert[_] } / ~'!' semantic_action { Disallow[_] } / ~'~' semantic_action { Skip[_] }
list <- list_term ~(‘*’ ‘,’) list_term { list0 *_ }
/ list_term ~('+' ',') list_term { list1 *_ } / list_term repeat_count ~',' list_term <ListParser>
list_term <- prefixed
/ prefixable / expected 'term'
prefixed <- ~‘&’ prefixable <Assert>
/ ~'!' prefixable <Disallow> / ~'~' prefixable <Skip> / ~'@' prefixable <Token>
prefixable <- prefixed / suffixable
/ expected 'primary'
suffixed <- suffixable ~‘?’ { optional _ }
/ suffixable ~'*' !',' { zero_or_more _ } / suffixable ~'+' !',' { one_or_more _ } / suffixable repeat_count !',' <Repeat>
repeat_count <- @DIGIT+ ~‘..’ @DIGIT+ { _.map {|s| s.to_i } }
/ @DIGIT+ ~'..' { [_.to_i, nil] } / @DIGIT+ { [_.to_i] * 2 }
suffixable <- suffixed / primary
/ expected 'primary'
primary <- ~‘(’ expression ~‘)’
/ atom
atom <- ~‘EOF` <Eof>
/ ~`E` <ESymbol> / ~`super` { Super[:pending] } / posix_class { posix_class _ } / identifier !'<-' <Apply> / literal { literal _ } / word_literal { word_literal _ } / class { char_class _ } / back_reference <BackReference> / ~'.' { Match[/./] }
%inline
fail_keyword <- ‘fail` / `fail_rule` / `fail_parse` / `expected`
fail_arg <- ~‘(’ literal ~‘)’
/ literal
posix_class <- ‘ALNUM`
/ `ALPHA` / `ASCII` / `BLANK` / `CNTRL` / `DIGIT` / `GRAPH` / `LOWER` / `PRINT` / `PUNCT` / `SPACE` / `UPPER` / `XDIGIT` / `WORD`
literal <- @(‘“’ (‘\’ . / [^”])* ‘“’)
/ @("'" ('\\' . / [^'])* "'") / @('%(' ('\\' . / [^)])* ')') / @('%{' ('\\' . / [^}])* '}') / @('%[' ('\\' . / [^\]])* ']') / @('%<' ('\\' . / [^>])* '>') / @('%' q:PUNCT ('\\' . / !$q .)* $q)
word_literal <- @(“‘” (’\‘ . / [^`])* “`”)
class <- @(‘[’ (!‘]’ range)+ ‘]’)
name <- var_name
/ constant
identifier <- !‘EOF` @(ALPHA WORD*)
back_reference <- @(‘$’ LOWER WORD*)
var_name <- @(LOWER WORD*)
constant <- @((UPPER WORD* ‘::’)* UPPER WORD*)
const_name <- @(UPPER WORD*)
%fragments
range <- ‘[:’ posix_name ‘:]’
/ class_char ('-' class_char)?
posix_name <- ‘alnum`
/ `alpha` / `ascii` / `blank` / `cntrl` / `digit` / `graph` / `lower` / `print` / `punct` / `space` / `upper` / `xdigit`
class_char <- ‘\’ [0-3] [0-7] [0-7]
/ '\\x' XDIGIT XDIGIT / '\\' . / [^\\\]]
eol <- ~(BLANK* (EOF / ‘;’ / “r”? “n” / comment))
comment <- ~(‘#’ [^n]*)