mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-03-16 17:00:53 +00:00
sketch out macro expansion more
This commit is contained in:
parent
7bf7f686d9
commit
3ddc0dfe02
@ -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(())
|
||||
}
|
||||
}
|
||||
|
87
src/normalize/macro_expand.rs
Normal file
87
src/normalize/macro_expand.rs
Normal 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));
|
||||
}
|
||||
}
|
@ -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
2
src/normalize/util.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub struct SymbolKey {
|
||||
}
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user