summaryrefslogtreecommitdiffstats
path: root/vendor/pest_meta/src/grammar.pest
blob: 0d03ba8998e2eb62e0f5a683906ab55d76a584e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

grammar_rules = _{ SOI ~ grammar_rule+ ~ EOI }

grammar_rule = {
    identifier ~ assignment_operator ~ modifier? ~
    opening_brace ~ expression ~ closing_brace
}

assignment_operator = { "=" }
opening_brace       = { "{" }
closing_brace       = { "}" }
opening_paren       = { "(" }
closing_paren       = { ")" }
opening_brack       = { "[" }
closing_brack       = { "]" }

modifier = _{
    silent_modifier |
    atomic_modifier |
    compound_atomic_modifier |
    non_atomic_modifier
}

silent_modifier          = { "_" }
atomic_modifier          = { "@" }
compound_atomic_modifier = { "$" }
non_atomic_modifier      = { "!" }

expression =  { term ~ (infix_operator ~ term)* }
term       =  { prefix_operator* ~ node ~ postfix_operator* }
node       = _{ opening_paren ~ expression ~ closing_paren | terminal }
terminal   = _{ _push | peek_slice | identifier | string | insensitive_string | range }

prefix_operator  = _{ positive_predicate_operator | negative_predicate_operator }
infix_operator   = _{ sequence_operator | choice_operator }
postfix_operator = _{
    optional_operator |
    repeat_operator |
    repeat_once_operator |
    repeat_exact |
    repeat_min |
    repeat_max |
    repeat_min_max
}

positive_predicate_operator = { "&" }
negative_predicate_operator = { "!" }
sequence_operator           = { "~" }
choice_operator             = { "|" }
optional_operator           = { "?" }
repeat_operator             = { "*" }
repeat_once_operator        = { "+" }

repeat_exact   = { opening_brace ~ number ~ closing_brace }
repeat_min     = { opening_brace ~ number ~ comma ~ closing_brace }
repeat_max     = { opening_brace ~ comma ~ number ~ closing_brace }
repeat_min_max = { opening_brace ~ number ~ comma ~ number ~ closing_brace }

number = @{ '0'..'9'+ }
integer = @{ number | "-" ~ "0"* ~ '1'..'9' ~ number? }

comma = { "," }

_push = { "PUSH" ~ opening_paren ~ expression ~ closing_paren }
peek_slice = { "PEEK" ~ opening_brack ~ integer? ~ range_operator ~ integer? ~ closing_brack }

identifier = @{ !"PUSH" ~ ("_" | alpha) ~ ("_" | alpha_num)* }
alpha      = _{ 'a'..'z' | 'A'..'Z' }
alpha_num  = _{ alpha | '0'..'9' }

string             = ${ quote ~ inner_str ~ quote }
insensitive_string =  { "^" ~ string }
range              =  { character ~ range_operator ~ character }
character          = ${ single_quote ~ inner_chr ~ single_quote }

inner_str = @{ (!("\"" | "\\") ~ ANY)* ~ (escape ~ inner_str)? }
inner_chr = @{ escape | ANY }
escape    = @{ "\\" ~ ("\"" | "\\" | "r" | "n" | "t" | "0" | "'" | code | unicode) }
code      = @{ "x" ~ hex_digit{2} }
unicode   = @{ "u" ~ opening_brace ~ hex_digit{2, 6} ~ closing_brace }
hex_digit = @{ '0'..'9' | 'a'..'f' | 'A'..'F' }

quote          = { "\"" }
single_quote   = { "'" }
range_operator = { ".." }

newline    = _{ "\n" | "\r\n" }
WHITESPACE = _{ " " | "\t" | newline }
block_comment = _{ "/*" ~ (block_comment | !"*/" ~ ANY)* ~ "*/" }
COMMENT    = _{ block_comment | ("//" ~ (!newline ~ ANY)*) }