diff options
Diffstat (limited to 'chomp-macro')
-rw-r--r-- | chomp-macro/Cargo.toml | 18 | ||||
-rw-r--r-- | chomp-macro/src/lib.rs | 42 | ||||
-rw-r--r-- | chomp-macro/tests/nibble_exp.rs | 81 | ||||
-rw-r--r-- | chomp-macro/tests/ratata.rs | 15 | ||||
-rw-r--r-- | chomp-macro/tests/regex.rs | 27 | ||||
-rw-r--r-- | chomp-macro/tests/regex_fix.rs | 11 | ||||
-rw-r--r-- | chomp-macro/tests/sheep.rs | 15 |
7 files changed, 209 insertions, 0 deletions
diff --git a/chomp-macro/Cargo.toml b/chomp-macro/Cargo.toml new file mode 100644 index 0000000..bc8dce0 --- /dev/null +++ b/chomp-macro/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "chomp-macro" +version = "0.1.0" +authors = ["Greg Brown <gmb60@cam.ac.uk>"] +edition = "2018" + +[dependencies] +chomp = {path = ".."} + +[dependencies.syn] +version = "1" +features = ["parsing", "proc-macro"] + +[dev-dependencies] +chewed = {path = "../chewed"} + +[lib] +proc_macro = true diff --git a/chomp-macro/src/lib.rs b/chomp-macro/src/lib.rs new file mode 100644 index 0000000..d58bbdc --- /dev/null +++ b/chomp-macro/src/lib.rs @@ -0,0 +1,42 @@ +use chomp::{ + chomp::{ + check::{InlineCalls, TypeCheck}, + context::Context, + visit::Visitable, + }, + lower::{rust::RustBackend, Backend, GenerateCode}, + nibble::cst::File, +}; +use proc_macro::{Span, TokenStream}; +use syn::Error; + +#[proc_macro] +pub fn nibble(item: TokenStream) -> TokenStream { + syn::parse(item) + .and_then(|nibble: File| { + nibble + .convert() + .ok_or_else(|| todo!()) + }) + .and_then(|(funs, goal)| { + funs.into_iter() + .try_rfold(goal, |goal, function| { + goal.fold(&mut InlineCalls::new(function)) + }) + .map_err(Error::from) + }) + .and_then(|expr| { + let mut context = Context::default(); + expr.fold(&mut TypeCheck { + context: &mut context, + }) + .map_err(Error::from) + }) + .map(|typed| { + let mut backend = RustBackend::default(); + let id = typed.gen(&mut backend); + backend.emit_code(id) + }) + .unwrap_or_else(Error::into_compile_error) + .into() +} diff --git a/chomp-macro/tests/nibble_exp.rs b/chomp-macro/tests/nibble_exp.rs new file mode 100644 index 0000000..7e31e6a --- /dev/null +++ b/chomp-macro/tests/nibble_exp.rs @@ -0,0 +1,81 @@ +chomp_macro::nibble! { + let opt(x) = _ | x; + let plus(x) = [plus](x . opt(plus)); + let star(x) = [star](opt(x . star)); + + let Pattern_Whitespace = "\n"|" "; + + let XID_Start = + "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | + "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | + "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | + "y" | "z" | + "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | + "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | + "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | + "Y" | "Z" ; + let XID_Continue = + XID_Start | "_" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; + + let literal_char = XID_Continue; + + let ws = star(Pattern_Whitespace); + let must_ws = plus(Pattern_Whitespace); + + let punctuated(x, p) = [rec](x . opt(p . ws . rec)); + let list(x) = "(" . ws . [rec](x . opt("," . ws . opt(rec))) . ")"; + + let epsilon = "_"; + let ident = XID_Start . star(XID_Continue); + let literal = "\"" . plus(literal_char) . "\""; + let parens(expr) = "(" . ws . expr . ")"; + let fix(expr) = "[" . ws . ident . ws . "]" . ws . parens(expr); + + let term(expr) = + epsilon . ws + | literal . ws + | parens(expr) . ws + | fix(expr) . ws + | ident . ws . opt(list(expr) . ws) + ; + + let cat(expr) = punctuated(term(expr), "."); + let alt(expr) = punctuated(cat(expr), "|"); + let expr = [expr](alt(expr)); + match expr; +} + +#[test] +fn exp_epsilon() { + Ast::parse_str("_").unwrap(); +} + +#[test] +fn exp_literal() { + Ast::parse_str(r#""foo""#).unwrap(); +} + +#[test] +fn exp_cat() { + Ast::parse_str(r#""a" . "b""#).unwrap(); +} + +#[test] +fn exp_alt() { + Ast::parse_str(r#""a" | "b""#).unwrap(); +} + +#[test] +fn exp_ident() { + Ast::parse_str("foo").unwrap(); +} + +#[test] +fn exp_call() { + Ast::parse_str(r#"opt("foo")"#).unwrap(); +} + +#[test] +fn exp_fix() { + Ast::parse_str(r#"[rec](_ | "a" . rec)"#).unwrap(); +} diff --git a/chomp-macro/tests/ratata.rs b/chomp-macro/tests/ratata.rs new file mode 100644 index 0000000..869ad61 --- /dev/null +++ b/chomp-macro/tests/ratata.rs @@ -0,0 +1,15 @@ +chomp_macro::nibble! { + let opt(x) = _ | x; + let plus(x) = [rec](x . opt(rec)); + match plus(("r" | "t") . "a"); +} + +#[test] +fn ratata_ratata() { + Ast::parse_str("ratata").unwrap(); +} + +#[test] +fn ratata_ratarataratatata() { + Ast::parse_str("ratarataratatata").unwrap(); +} diff --git a/chomp-macro/tests/regex.rs b/chomp-macro/tests/regex.rs new file mode 100644 index 0000000..1e831b4 --- /dev/null +++ b/chomp-macro/tests/regex.rs @@ -0,0 +1,27 @@ +chomp_macro::nibble! { + let opt(x) = _ | x; + let plus(x) = [plus](x . opt(plus)); + let star(x) = [star](opt(x . star)); + + match plus("a") . star("b"); +} + +#[test] +fn regex_a() { + Ast::parse_str("a").unwrap(); +} + +#[test] +fn regex_ab() { + Ast::parse_str("ab").unwrap(); +} + +#[test] +fn regex_aa() { + Ast::parse_str("aa").unwrap(); +} + +#[test] +fn regex_aaaabbb() { + Ast::parse_str("aaaabbb").unwrap(); +} diff --git a/chomp-macro/tests/regex_fix.rs b/chomp-macro/tests/regex_fix.rs new file mode 100644 index 0000000..9842484 --- /dev/null +++ b/chomp-macro/tests/regex_fix.rs @@ -0,0 +1,11 @@ +chomp_macro::nibble! { + let opt(x) = _ | x; + let ws = [star](opt(" " . star)); + + match [rec]("a" . opt("." . ws . rec)); +} + +#[test] +fn regex_fix_cat() { + Ast::parse_str(r#"a. a"#).unwrap(); +} diff --git a/chomp-macro/tests/sheep.rs b/chomp-macro/tests/sheep.rs new file mode 100644 index 0000000..862e810 --- /dev/null +++ b/chomp-macro/tests/sheep.rs @@ -0,0 +1,15 @@ +chomp_macro::nibble! { + let opt(x) = _ | x; + let plus(x) = [rec](x . opt(rec)); + match "ba" . plus("a"); +} + +#[test] +fn baa() { + Ast::parse_str("baa").unwrap(); +} + +#[test] +fn baaaaaaaaaaaaaaa() { + Ast::parse_str("baaaaaaaaaaaaaaa").unwrap(); +} |