peginator 0.2.4

PEG parser generator for creating ASTs in Rust
Documentation
# 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 =
    '"' {!'"' body:StringItem } '"' |
    "'" {!"'" body:StringItem } "'"
;

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 |
    @:CheckDirective
;
StringDirective = "@string";
CharDirective = "@char";
NoSkipWsDirective = "@no_skip_ws";
ExportDirective = "@export";
PositionDirective = "@position";
MemoizeDirective = "@memoize";
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';