mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-03-16 17:00:53 +00:00
Macro definitions, references.
This commit is contained in:
parent
30e3274477
commit
3305bbdd3e
@ -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>),
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user