sketch out macro expansion more

This commit is contained in:
Niko Matsakis 2015-06-15 10:33:11 -04:00
parent 7bf7f686d9
commit 3ddc0dfe02
5 changed files with 160 additions and 6 deletions

View File

@ -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(())
}
}

View File

@ -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));
}
}

View File

@ -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*:

2
src/normalize/util.rs Normal file
View File

@ -0,0 +1,2 @@
pub struct SymbolKey {
}

View File

@ -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;