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