Macro definitions, references.

This commit is contained in:
Niko Matsakis 2015-06-15 07:11:32 -04:00
parent 30e3274477
commit 3305bbdd3e
4 changed files with 106 additions and 38 deletions

View File

@ -39,20 +39,20 @@ grammar Type<'input, T> {
// or guard expressions.
// Example 1: comma-separated list with optional trailing comma.
Comma<$A>: Vec<$A> = {
~v:(~$A ",")* ~e:(~$A ,?)?> => {
let mut v = v; v.push(e); v
}
Comma<E>: Vec<E> = {
~v:(~E ",")* ~e:E? => {
let mut v = v;
if let Some(e) = e { v.push(e); }
v
};
};
// Example 2: conditional patterns
Expr<$M>: Expr = {
Expr<M>: Expr = {
~Expr "(" ~Comma<Expr> ")" => Expr::CallExpr(~~~);
ID if $M != "NO_ID" => {
ID if M !~ "NO_ID" => {
};
};
}
```
@ -83,6 +83,7 @@ pub struct TokenTypeData {
#[derive(Clone, Debug)]
pub struct NonterminalData {
pub name: InternedString,
pub args: Vec<InternedString>, // macro arguments
pub type_decl: Option<String>,
pub alternatives: Vec<Alternative>
}
@ -106,6 +107,9 @@ pub enum Symbol {
// foo
Nonterminal(InternedString),
// foo<..>
Macro(InternedString, Vec<Symbol>),
// X+
Plus(Box<Symbol>),

View File

@ -13,13 +13,22 @@ pub fn normalize(input: &pt::Grammar) -> Result<pt::Grammar> {
// Expands macros
//
// X = ...1 Vec<X> ...2
// X = ...1 Comma<X> ...2
//
// to
//
// X = ...1 Vec_X ...2
// Vec_X = ...;
mod macro_expand;
// Comma_X: Vec<<X>> = ...;
//
// AFTER THIS POINT: No more macros or macro references, though type
// indirections may occur.
// mod macro_expand;
// Computes types where the user omitted them (or
// from macro byproducts).
//
// AFTER THIS POINT: All explicit, simple types.
// mod tyinfer;
// Converts
//
@ -29,7 +38,15 @@ mod macro_expand;
//
// X = ...1 A_B_C ...2
// A_B_C = A B C
mod nonterminalize;
//
// AFTER THIS POINT: No more Symbol::Expr remain.
// mod nonterminalize;
// Synthesizes action code for all nonterminals.
//
// AFTER THIS POINT: All nonterminals have action code, and all
// Symbol::Choose and Symbol::Name are removed.
// mod action;
// Converts
//
@ -39,7 +56,9 @@ mod nonterminalize;
//
// X = ...1 ...2
// | ...1 Y+ ...2
mod remove_star;
//
// AFTER THIS POINT: No more Symbol::Star remain.
// mod remove_star;
// Converts X+ to a new terminal X_PLUS like:
//
@ -47,7 +66,9 @@ mod remove_star;
// <e:X> => { vec![x] }
// <v:X_PLUS> <e:X> => { let mut v = v; v.push(e); v }
// }
mod remove_plus;
//
// AFTER THIS POINT: No more Symbol::Plus remain.
// mod remove_plus;
// Converts
//
@ -57,9 +78,6 @@ mod remove_plus;
//
// X = ...1 ...2
// | ...1 Y ...2
mod remove_question;
// Infers types for all nonterminals where possible, or reports a
// suitable error.
mod actionify;
//
// AFTER THIS POINT: No more Symbol::Question remain.
// mod remove_question;

View File

@ -26,12 +26,29 @@ rusty_peg! {
(<from:LITERAL> "=>" <to:LITERAL> ";") => (from, to);
NONTERMINAL: GrammarItem =
(<n:ID> <t:[NONTERMINAL_TYPE]> "=" <a:ALTERNATIVES>) => {
GrammarItem::Nonterminal(NonterminalData { name: n,
(<n:NONTERMINAL_NAME> <t:[NONTERMINAL_TYPE]> "=" <a:ALTERNATIVES>) => {
GrammarItem::Nonterminal(NonterminalData { name: n.0,
args: n.1,
type_decl: t,
alternatives: a })
};
NONTERMINAL_NAME: (InternedString, Vec<InternedString>) =
(NONTERMINAL_NAME_MACRO / NONTERMINAL_NAME_SIMPLE);
NONTERMINAL_NAME_SIMPLE: (InternedString, Vec<InternedString>) =
(<a:ID>) => (a, vec![]);
NONTERMINAL_NAME_MACRO: (InternedString, Vec<InternedString>) =
(<a:ID> "<" <b:{NONTERMINAL_NAME_MACRO1}> <c:[ID]> ">") => {
let mut args = b;
if let Some(c) = c { args.push(c); }
(a, args)
};
NONTERMINAL_NAME_MACRO1: InternedString =
(<a:ID> ",") => a;
NONTERMINAL_TYPE: String =
(":" <s:NOT_EQ>) => s.to_string();
@ -66,7 +83,17 @@ rusty_peg! {
"?" => Symbol::Question(Box::new(lhs)));
SYMBOL0: Symbol =
(TERMINAL_SYMBOL / NT_SYMBOL / EXPR_SYMBOL / NAMED_SYMBOL / CHOSEN_SYMBOL);
(MACRO_SYMBOL / TERMINAL_SYMBOL / NT_SYMBOL / EXPR_SYMBOL /
NAMED_SYMBOL / CHOSEN_SYMBOL);
MACRO_SYMBOL: Symbol =
(<l:ID> "<" <m:{MACRO_ARG_START}> <n:[SYMBOL]> ">") => {
let mut args = m;
if let Some(n) = n { args.push(n); }
Symbol::Macro(l, args)
};
MACRO_ARG_START: Symbol = (<s:SYMBOL> ",") => s;
TERMINAL_SYMBOL: Symbol =
(<l:LITERAL>) => Symbol::Terminal(l);
@ -204,3 +231,8 @@ fn parse_symbol(text: &str) -> Result<Symbol,rusty_peg::Error> {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&SYMBOL, &mut parser, text)
}
fn parse_nonterminal(text: &str) -> Result<GrammarItem,rusty_peg::Error> {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&NONTERMINAL, &mut parser, text)
}

View File

@ -1,70 +1,84 @@
use super::{parse_type_name, parse_grammar, parse_alternative, parse_symbol};
#[test]
fn type_name() {
let x = parse_type_name("parser::Enum<'l,T>");
let x = super::parse_type_name("parser::Enum<'l,T>");
assert_eq!(x.reference(), "::parser::Enum<'l, T>");
}
#[test]
fn empty_grammar() {
parse_grammar(r#"grammar Foo { }"#).unwrap();
super::parse_grammar(r#"grammar Foo { }"#).unwrap();
}
#[test]
fn alternative() {
parse_alternative(r#"Alt => Bar;"#).unwrap();
super::parse_alternative(r#"Alt => Bar;"#).unwrap();
}
#[test]
fn symbol() {
parse_symbol(r#"Alt"#).unwrap();
super::parse_symbol(r#"Alt"#).unwrap();
}
#[test]
fn nonterminal0() {
parse_grammar(r#"grammar Foo { Expr = Alt; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = Alt; }"#).unwrap();
}
#[test]
fn paren() {
parse_grammar(r#"grammar Foo { Expr = (Alt); }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = (Alt); }"#).unwrap();
}
#[test]
fn paren_with_plus() {
parse_grammar(r#"grammar Foo { Expr = (Alt)+; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = (Alt)+; }"#).unwrap();
}
#[test]
fn paren_with_plus_and_anon() {
parse_grammar(r#"grammar Foo { Expr = (~Alt)+; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = (~Alt)+; }"#).unwrap();
}
#[test]
fn named_choice() {
parse_grammar(r#"grammar Foo { Expr = ~n:Alt; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = ~n:Alt; }"#).unwrap();
}
#[test]
fn named_choice_plus() {
parse_grammar(r#"grammar Foo { Expr = ~Alt+; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { Expr = ~Alt+; }"#).unwrap();
}
#[test]
fn token_expr() {
parse_grammar(r#"grammar Foo { token Expr where { "foo" => "bar"; }; }"#).unwrap();
super::parse_grammar(r#"grammar Foo { token Expr where { "foo" => "bar"; }; }"#).unwrap();
}
#[test]
fn map1() {
parse_grammar(
super::parse_grammar(
r#"grammar Foo { Expr = ~n:Alt+ => { { foo } }; }"#).unwrap();
}
#[test]
fn mapN() {
parse_grammar(
super::parse_grammar(
r#"grammar Foo { Expr = { Bar => { Baz }; X ~n:Bar => { Y }; }; }"#).unwrap();
}
#[test]
fn macro_symbols() {
super::parse_symbol(r#"Foo<Baz>"#).unwrap();
super::parse_symbol(r#"Foo<"Baz">"#).unwrap();
super::parse_symbol(r#"Foo<"Baz"+>"#).unwrap();
super::parse_symbol(r#"Foo<"Baz"+, "Balooga">"#).unwrap();
super::parse_symbol(r#"Foo<"Baz"+, ("Balooga" Potato),>"#).unwrap();
}
#[test]
fn macro_nt() {
super::parse_nonterminal(
r#"Comma<E>: Vec<E> = ~v:(~E ",")* ~e:E? => { let mut v = v; v.extend(e.into_iter()); v};"#)
.unwrap();
}