1// pest. The Elegant Parser
2// Copyright (c) 2018 Dragoș Tiselice
3//
4// Licensed under the Apache License, Version 2.0
5// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. All files in the project carrying such notice may not be copied,
8// modified, or distributed except according to those terms.
9
10grammar_rules = _{ SOI ~ grammar_rule+ ~ EOI }
11
12grammar_rule = {
13    identifier ~ assignment_operator ~ modifier? ~
14    opening_brace ~ expression ~ closing_brace
15}
16
17assignment_operator = { "=" }
18opening_brace       = { "{" }
19closing_brace       = { "}" }
20opening_paren       = { "(" }
21closing_paren       = { ")" }
22opening_brack       = { "[" }
23closing_brack       = { "]" }
24
25modifier = _{
26    silent_modifier |
27    atomic_modifier |
28    compound_atomic_modifier |
29    non_atomic_modifier
30}
31
32silent_modifier          = { "_" }
33atomic_modifier          = { "@" }
34compound_atomic_modifier = { "$" }
35non_atomic_modifier      = { "!" }
36
37expression =  { term ~ (infix_operator ~ term)* }
38term       =  { prefix_operator* ~ node ~ postfix_operator* }
39node       = _{ opening_paren ~ expression ~ closing_paren | terminal }
40terminal   = _{ _push | peek_slice | identifier | string | insensitive_string | range }
41
42prefix_operator  = _{ positive_predicate_operator | negative_predicate_operator }
43infix_operator   = _{ sequence_operator | choice_operator }
44postfix_operator = _{
45    optional_operator |
46    repeat_operator |
47    repeat_once_operator |
48    repeat_exact |
49    repeat_min |
50    repeat_max |
51    repeat_min_max
52}
53
54positive_predicate_operator = { "&" }
55negative_predicate_operator = { "!" }
56sequence_operator           = { "~" }
57choice_operator             = { "|" }
58optional_operator           = { "?" }
59repeat_operator             = { "*" }
60repeat_once_operator        = { "+" }
61
62repeat_exact   = { opening_brace ~ number ~ closing_brace }
63repeat_min     = { opening_brace ~ number ~ comma ~ closing_brace }
64repeat_max     = { opening_brace ~ comma ~ number ~ closing_brace }
65repeat_min_max = { opening_brace ~ number ~ comma ~ number ~ closing_brace }
66
67number = @{ '0'..'9'+ }
68integer = @{ number | "-" ~ "0"* ~ '1'..'9' ~ number? }
69
70comma = { "," }
71
72_push = { "PUSH" ~ opening_paren ~ expression ~ closing_paren }
73peek_slice = { "PEEK" ~ opening_brack ~ integer? ~ range_operator ~ integer? ~ closing_brack }
74
75identifier = @{ !"PUSH" ~ ("_" | alpha) ~ ("_" | alpha_num)* }
76alpha      = _{ 'a'..'z' | 'A'..'Z' }
77alpha_num  = _{ alpha | '0'..'9' }
78
79string             = ${ quote ~ inner_str ~ quote }
80insensitive_string =  { "^" ~ string }
81range              =  { character ~ range_operator ~ character }
82character          = ${ single_quote ~ inner_chr ~ single_quote }
83
84inner_str = @{ (!("\"" | "\\") ~ ANY)* ~ (escape ~ inner_str)? }
85inner_chr = @{ escape | ANY }
86escape    = @{ "\\" ~ ("\"" | "\\" | "r" | "n" | "t" | "0" | "'" | code | unicode) }
87code      = @{ "x" ~ hex_digit{2} }
88unicode   = @{ "u" ~ opening_brace ~ hex_digit{2, 6} ~ closing_brace }
89hex_digit = @{ '0'..'9' | 'a'..'f' | 'A'..'F' }
90
91quote          = { "\"" }
92single_quote   = { "'" }
93range_operator = { ".." }
94
95newline    = _{ "\n" | "\r\n" }
96WHITESPACE = _{ " " | "\t" | newline }
97block_comment = _{ "/*" ~ (block_comment | !"*/" ~ ANY)* ~ "*/" }
98COMMENT    = _{ block_comment | ("//" ~ (!newline ~ ANY)*) }
99