forked from rust-lang/gll
-
Notifications
You must be signed in to change notification settings - Fork 2
/
build.rs
122 lines (110 loc) · 3.6 KB
/
build.rs
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
extern crate indexing;
extern crate ordermap;
// HACK(eddyb) bootstrap by including a subset of the `gll` crate.
#[path = "src/generate/mod.rs"]
mod generate;
#[path = "src/grammar.rs"]
mod grammar;
#[path = "src/scannerless.rs"]
mod scannerless;
use grammar::{call, eat, negative_lookahead};
use std::env;
use std::fs;
use std::path::PathBuf;
type Grammar = scannerless::Grammar<&'static str>;
// HACK(eddyb) more explicit subset of the grammar, for bootstrapping.
macro_rules! rule {
({ $start:tt ..= $end:tt }) => {
eat($start..=$end)
};
({ ! $pat:tt }) => {
negative_lookahead($pat)
};
({ ! $start:tt ..= $end:tt }) => {
negative_lookahead($start..=$end)
};
($rule:ident) => {
call(stringify!($rule))
};
({ $name:ident : $rule:tt }) => {
rule!($rule).field(stringify!($name))
};
({ $rule:tt ? }) => {
rule!($rule).opt()
};
({ $elem:tt * }) => {
rule!($elem).repeat_many(None)
};
({ $elem:tt + }) => {
rule!($elem).repeat_more(None)
};
({ $elem:tt + % $sep:tt }) => {
rule!($elem).repeat_more(Some(rule!($sep)))
};
({ $rule0:tt $(| $rule:tt)+ }) => {
rule!($rule0) $(| rule!($rule))+
};
({ $rule0:tt $($rule:tt)* }) => {
rule!($rule0) $(+ rule!($rule))*
};
($pat:expr) => {
eat($pat)
};
}
macro_rules! grammar {
($($rule_name:ident = $($rule:tt)|+;)*) => ({
let mut grammar = Grammar::new();
$(grammar.define(stringify!($rule_name), rule!({ $($rule)|+ }));)*
grammar
})
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let mut grammar = grammar!{
// Lexical grammar.
Whitespace = {
{{
" " | "\t" | "\n" | "\r" |
{ "//" {{ {!"\n"} .. }*} "\n" } |
{ "/*" {{ {!"*/"} .. }*} "*/" }
}*}
{!" "} {!"\t"} {!"\n"} {!"\r"} {!"//"} {!"/*"}
};
Shebang = { "#!" {{ {!"\n"} .. }*} "\n" };
IdentStart = {'a'..='z'} | {'A'..='Z'} | "_";
IdentCont = IdentStart | {'0'..='9'};
NotIdent = { {!'a'..='z'} {!'A'..='Z'} {!"_"} {!'0'..='9'} };
Ident = { IdentStart {IdentCont*} NotIdent };
StrLit = { "\"" {{ { {!"\\"} {!"\""} .. } | { "\\" Escape } }*} "\"" };
CharLit = { "'" { { {!"\\"} {!"'"} .. } | { "\\" Escape } } "'" };
Escape = "t" | "n" | "r" | "\\" | "'" | "\"";
};
grammar.extend(
grammar!{
// Main grammar.
Grammar = { {Shebang?} {rules:{RuleDef*}} Whitespace };
RuleDef = { {name:Ident} "=" {rule:Or} ";" };
Or = {{"|"?} {rules:{Concat+ % "|"}}};
Concat = {rules:{Rule+}};
Rule = { {{ {field:Ident} ":" }?} {rule:Primary} {{modifier:Modifier}?} };
Primary =
{Eat:Pattern} |
{NegativeLookahead:{ "!" {pat:Pattern} }} |
{Call:Ident} |
{Group:{ "{" {{or:Or}?} "}" }};
Modifier =
{Opt:"?"} |
{Repeat:{ {repeat:Repeat} {{ "%" {sep:Primary} }?} }};
Repeat =
{Many:"*"} |
{More:"+"};
Pattern =
{Str:StrLit} |
{CharRange:{ {{start:CharLit}?} ".." {{end:CharLit}?} }} |
{CharRangeInclusive:{ {{start:CharLit}?} "..=" {end:CharLit} }};
}
.insert_whitespace(grammar::call("Whitespace")),
);
fs::write(&out_dir.join("parse_grammar.rs"), grammar.generate_rust()).unwrap();
}