extern crate indexing;
extern crate ordermap;
#[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>;
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!{
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!{
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();
}