# Copyright (C) 2022, Alex Badics
# This file is part of peginator
# Licensed under the MIT license. See LICENSE file in the project root for details.
@export
Grammar = {(rules:Rule | rules:CharRule | rules:ExternRule) ";"} $ ;
Rule = {directives:DirectiveExpression} name:Identifier "=" definition:Choice;
CharRule = {directives:CheckDirective} CharDirective {directives:CheckDirective} name:Identifier "=" choices:CharRulePart {"|" choices:CharRulePart };
CharRulePart = @:CharacterRange | @:CharRangePart | @:Identifier;
ExternRule = directive:ExternDirective name:Identifier;
Choice = choices:Sequence {"|" choices:Sequence};
Sequence = { parts:DelimitedExpression };
Group = "(" body:Choice ")";
Optional = "[" body:Choice "]";
Closure = "{" body:Choice "}" [at_least_one:AtLeastOneMarker];
AtLeastOneMarker = '+';
NegativeLookahead = "!" expr:*DelimitedExpression;
PositiveLookahead = "&" expr:*DelimitedExpression;
CharacterRange = from:CharRangePart ".." to:CharRangePart;
@no_skip_ws
CharRangePart = "'" @:StringItem "'";
@no_skip_ws
StringLiteral =
[insensitive:CaseInsensitiveMarker]
(
'"' {!'"' body:StringItem } '"' |
"'" {!"'" body:StringItem } "'"
)
;
CaseInsensitiveMarker = 'i';
Field = [name:Identifier ":" [boxed:BoxMarker]] typ:Identifier;
BoxMarker = '*';
OverrideField = "@" ":" typ:Identifier;
IncludeRule = ">" rule:Identifier;
DelimitedExpression =
@:Group |
@:Optional |
@:Closure |
@:NegativeLookahead |
@:PositiveLookahead |
@:CharacterRange |
@:StringLiteral |
@:EndOfInput |
@:OverrideField |
@:IncludeRule |
@:Field
;
@string
@no_skip_ws
Identifier = {IdentifierChar}+;
@char
IdentifierChar = 'a'..'z' | 'A'..'Z' | '0'..'9' | '_';
@no_skip_ws
StringItem = '\\' (@:SimpleEscape | @:HexaEscape | @:Utf8Escape) | !'\\' @:char ;
@no_skip_ws
SimpleEscape =
@:SimpleEscapeNewline |
@:SimpleEscapeCarriageReturn |
@:SimpleEscapeTab |
@:SimpleEscapeBackslash |
@:SimpleEscapeQuote |
@:SimpleEscapeDQuote
;
@no_skip_ws
SimpleEscapeNewline = 'n';
@no_skip_ws
SimpleEscapeCarriageReturn = 'r';
@no_skip_ws
SimpleEscapeTab = 't';
@no_skip_ws
SimpleEscapeBackslash = '\\';
@no_skip_ws
SimpleEscapeQuote = "'";
@no_skip_ws
SimpleEscapeDQuote = '"';
@no_skip_ws
HexaEscape = 'x' c1:HexChar c2:HexChar;
@char
HexChar = '0'..'9' | 'a'..'f' | 'A'..'F';
@no_skip_ws
Utf8Escape =
'u' '{' c1:HexChar [c2:HexChar [c3:HexChar [c4:HexChar [c5:HexChar [c6:HexChar ]]]]] '}' |
'u' c1:HexChar c2:HexChar c3:HexChar c4:HexChar |
'U' '0' '0' c1:HexChar c2:HexChar c3:HexChar c4:HexChar c5:HexChar c6:HexChar
;
DirectiveExpression =
@:StringDirective |
@:NoSkipWsDirective |
@:ExportDirective |
@:PositionDirective |
@:MemoizeDirective |
@:LeftrecDirective |
@:CheckDirective
;
StringDirective = "@string";
CharDirective = "@char";
NoSkipWsDirective = "@no_skip_ws";
ExportDirective = "@export";
PositionDirective = "@position";
MemoizeDirective = "@memoize";
LeftrecDirective = "@leftrec";
CheckDirective = "@check" "(" name_parts:RustNamePart { '::' name_parts:RustNamePart } ")";
ExternDirective =
"@extern" "("
name_parts:RustNamePart { '::' name_parts:RustNamePart }
[ '->' type_parts:RustNamePart { '::' type_parts:RustNamePart } ]
")"
;
@string
RustNamePart = {!( '-' | ')' |':' ) char}+;
EndOfInput = '$';
@no_skip_ws
Whitespace = {Comment | '\t' | '\n' | '\x0C' | '\r' | ' '};
@no_skip_ws
Comment = '#' {!'\n' char} '\n';