From 3ddc0dfe02abf49a8d0942bd225cba374aff5a65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Mon, 15 Jun 2015 10:33:11 -0400 Subject: [PATCH] sketch out macro expansion more --- src/grammar/parse_tree.rs | 71 ++++++++++++++++++++++++++-- src/normalize/macro_expand.rs | 87 +++++++++++++++++++++++++++++++++++ src/normalize/mod.rs | 2 +- src/normalize/util.rs | 2 + src/parser/mod.rs | 4 +- 5 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 src/normalize/macro_expand.rs create mode 100644 src/normalize/util.rs diff --git a/src/grammar/parse_tree.rs b/src/grammar/parse_tree.rs index 45e955a..f3722bb 100644 --- a/src/grammar/parse_tree.rs +++ b/src/grammar/parse_tree.rs @@ -60,6 +60,7 @@ grammar Type<'input, T> { */ use intern::InternedString; +use std::fmt::{Display, Formatter, Error}; #[derive(Clone, Debug)] pub struct Grammar { @@ -116,7 +117,18 @@ pub struct Alternative { pub condition: Option<Condition>, // => { code } - pub action: Option<String>, + pub action: Option<Action>, +} + +#[derive(Clone, Debug)] +pub enum Action { + // code provided by the user + User(String), + + // an index into a side-list of action fns, which is setup to take + // all of the values in this alternative as arguments, dropping + // the ones it doesn't care about. + Fn(u32), } #[derive(Clone, Debug)] @@ -136,7 +148,7 @@ pub enum Condition { #[derive(Clone, Debug)] pub enum Symbol { - // (<X> <Y>) etc + // (X Y) Expr(Vec<Symbol>), // "foo" @@ -146,7 +158,7 @@ pub enum Symbol { Nonterminal(InternedString), // foo<..> - Macro(InternedString, Vec<Symbol>), + Macro(MacroSymbol), // X+ Plus(Box<Symbol>), @@ -163,3 +175,56 @@ pub enum Symbol { // ~x:X Name(InternedString, Box<Symbol>), } + +#[derive(Clone, Debug)] +pub struct MacroSymbol { + pub name: InternedString, + pub args: Vec<Symbol> +} + +impl Symbol { + pub fn canonical_form(&self) -> String { + format!("{}", self) + } +} + +impl Display for Symbol { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + match *self { + Symbol::Expr(ref symbols) => + write!(fmt, "({})", Sep(" ", symbols)), + Symbol::Terminal(ref s) => + write!(fmt, "\"{}\"", s.to_string()), + Symbol::Nonterminal(ref s) => + write!(fmt, "{}", s), + Symbol::Macro(ref m) => + write!(fmt, "{}<{}>", m.name, Sep(", ", &m.args)), + Symbol::Plus(ref s) => + write!(fmt, "{}+", s), + Symbol::Question(ref s) => + write!(fmt, "{}?", s), + Symbol::Star(ref s) => + write!(fmt, "{}?", s), + Symbol::Choose(ref s) => + write!(fmt, "~{}", s), + Symbol::Name(n, ref s) => + write!(fmt, "~{}:{}", n, s), + } + } +} + +struct Sep<S>(&'static str, S); + +impl<'a,S:Display> Display for Sep<&'a Vec<S>> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + let &Sep(sep, vec) = self; + let mut elems = vec.iter(); + if let Some(elem) = elems.next() { + write!(fmt, "{}", elem); + while let Some(elem) = elems.next() { + write!(fmt, "{}{}", sep, elem); + } + } + Ok(()) + } +} diff --git a/src/normalize/macro_expand.rs b/src/normalize/macro_expand.rs new file mode 100644 index 0000000..938dab9 --- /dev/null +++ b/src/normalize/macro_expand.rs @@ -0,0 +1,87 @@ +use std::collections::HashMap; +use grammar::parse_tree::{Grammar, GrammarItem, MacroSymbol, Symbol}; + +pub fn expand_macros(input: pt::Grammar) { + let Grammar { type_name, items } = input; + let mut expander = MacroExpander::new(); +} + +struct MacroExpander { + expansion_stack: Vec<MacroSymbol>, + expansion_set: HashSet<InternedString>, +} + +impl MacroExpander { + fn new(items: Vec<GrammarItem>) -> MacroExpander { + MacroExpander { items: items, expansion_stack: Vec::new(), expansion_set: HashSet::new() } + } + + fn expand(&mut self, items: &mut Vec<GrammarItem>) { + let mut counter = 0; + loop { + // Find any macro uses in items added since last round and + // replace them in place with the expanded version: + for item in &mut items[counter..] { + self.replace(item); + } + counter = items.len(); + + // Drain macro queue: + } + } + + fn replace_item(&mut self, item: &mut GrammarItem) { + match *item { + GrammarItem::TokenType(..) => { } + GrammarItem::Nonterminal(ref data) => { + // Ignore macro definitions. They will be expanded in + // due course. + if !data.args.is_empty() { + return; + } + + for alternative in &mut data.alternatives { + self.replace_symbol(&mut alternative.symbol); + } + } + } + } + + fn replace_symbol(&mut self, symbol: &mut Symbol) { + let key; + + match *symbol { + Symbol::Macro(ref mut macro) => { + for sym in &mut macro.args { + self.replace(sym); + } + + key = symbol.canonical_form(); + if self.expansion_set.insert(key) { + self.expansion_stack.push(macro.clone()); + } + } + Symbol::Expr(ref mut syms) => { + for sym in syms { + self.replace_symbol(sym); + } + return; + } + Symbol::Terminal(_) | + Symbol::Nonterminal(_) => { + return; + } + Symbol::Plus(ref mut sym) | + Symbol::Question(ref mut sym) | + Symbol::Star(ref mut sym) | + Symbol::Choose(ref mut sym) | + Symbol::Name(_, ref mut sym) => { + self.replace_symbol(sym); + return; + } + } + + // we only get here if this is a macro expansion + *symbol = Symbol::Nonterminal(intern(key)); + } +} diff --git a/src/normalize/mod.rs b/src/normalize/mod.rs index 47ebe94..b227358 100644 --- a/src/normalize/mod.rs +++ b/src/normalize/mod.rs @@ -6,7 +6,7 @@ use grammar::parse_tree as pt; -pub fn normalize(input: &pt::Grammar) -> Result<pt::Grammar> { +pub fn normalize(input: pt::Grammar) -> Result<pt::Grammar> { } // These are executed *IN ORDER*: diff --git a/src/normalize/util.rs b/src/normalize/util.rs new file mode 100644 index 0000000..5e190ac --- /dev/null +++ b/src/normalize/util.rs @@ -0,0 +1,2 @@ +pub struct SymbolKey { +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 93309b9..be6556e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -70,7 +70,7 @@ rusty_peg! { IF_COND: Condition = ("if" <c:COND>) => c; - ACTION: String = ("=>" <b:CODE>) => b; + ACTION: Action = ("=>" <b:CODE>) => Action::User(b); // Conditions @@ -105,7 +105,7 @@ rusty_peg! { (<l:ID> "<" <m:{MACRO_ARG_START}> <n:[SYMBOL]> ">") => { let mut args = m; if let Some(n) = n { args.push(n); } - Symbol::Macro(l, args) + Symbol::Macro(MacroSymbol { name: l, args: args }) }; MACRO_ARG_START: Symbol = (<s:SYMBOL> ",") => s;