generate action code in macro expand

This commit is contained in:
Niko Matsakis 2015-06-17 15:02:34 -04:00
parent cc155debd7
commit 44d7050ddb
8 changed files with 107 additions and 28 deletions

View File

@ -1,5 +1,6 @@
//! The grammar definition.
pub mod nonce;
pub mod parse_tree;
pub mod repr;
// pub mod token;

27
src/grammar/nonce.rs Normal file
View File

@ -0,0 +1,27 @@
/*!
A NONCE is just a guaranteed unique identifier. We use it to create
persistent identity for alternatives as we transform the grammar.
*/
use std::cell::Cell;
thread_local! {
static NONCE: Cell<u32> = Cell::new(0)
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Nonce {
counter: u32
}
impl Nonce {
fn new() -> Nonce {
NONCE.with(|counter| {
let c = counter.get();
counter.set(c.checked_add(1).unwrap());
Nonce { counter: c }
})
}
}

View File

@ -63,3 +63,4 @@ impl Display for TypeRepr {
}
}
}

View File

@ -1,8 +1,10 @@
use std::collections::{HashMap, HashSet};
use intern::{intern, read, InternedString};
use grammar::parse_tree::{Alternative, Condition, ConditionOp, ExprSymbol, Grammar, GrammarItem,
MacroSymbol, NonterminalData, RepeatSymbol, Span, Symbol, TypeRef};
MacroSymbol, NonterminalData, RepeatOp, RepeatSymbol,
Span, Symbol, TypeRef};
use normalize::{NormResult, NormError};
use normalize::norm_util::{self, Symbols};
use regex::Regex;
use std::mem;
@ -67,7 +69,7 @@ impl MacroExpander {
Symbol::Macro(msym) =>
items.push(try!(self.expand_macro_symbol(msym))),
Symbol::Expr(expr) =>
items.push(self.expand_expr_symbol(expr)),
items.push(try!(self.expand_expr_symbol(expr))),
_ =>
assert!(false, "don't know how to expand `{:?}`", sym)
}
@ -110,6 +112,7 @@ impl MacroExpander {
return;
}
Symbol::Repeat(ref mut repeat) => {
// self.replace_repeat(repeat);
self.replace_symbol(&mut repeat.symbol);
return;
}
@ -132,6 +135,28 @@ impl MacroExpander {
}
}
fn replace_repeat(&mut self, repeat: &mut RepeatSymbol) {
match repeat.op {
RepeatOp::Star => {
// Convert X* to X+? and recurse. Annoyingly, we have
// to clone for this, due to not being able to move
// out from `&mut` pointers.
*repeat = RepeatSymbol {
op: RepeatOp::Question,
symbol: Symbol::Repeat(Box::new(RepeatSymbol {
op: RepeatOp::Plus,
symbol: repeat.symbol.clone()
}))
};
return self.replace_repeat(repeat);
}
RepeatOp::Question |
RepeatOp::Plus => {
self.replace_symbol(&mut repeat.symbol);
}
}
}
///////////////////////////////////////////////////////////////////////////
// Macro expansion
@ -301,18 +326,44 @@ impl MacroExpander {
///////////////////////////////////////////////////////////////////////////
// Expr expansion
fn expand_expr_symbol(&mut self, expr: ExprSymbol) -> GrammarItem {
fn expand_expr_symbol(&mut self, expr: ExprSymbol) -> NormResult<GrammarItem> {
let name = intern(&expr.canonical_form());
GrammarItem::Nonterminal(NonterminalData {
let ty_ref = match norm_util::analyze_expr(&expr) {
Symbols::Named(names) => {
let (ex_id, ex_sym) = names[0];
return_err!(
expr.span,
"named symbols like `~{}:{}` are only allowed at the top-level of a nonterminal",
ex_id, ex_sym)
}
Symbols::Anon(syms) => {
maybe_tuple(
syms.into_iter()
.cloned()
.map(TypeRef::OfSymbol)
.collect())
}
};
Ok(GrammarItem::Nonterminal(NonterminalData {
span: expr.span,
name: name,
args: vec![],
type_decl: None,
type_decl: Some(ty_ref),
alternatives: vec![Alternative { span: expr.span,
expr: expr,
condition: None,
action: None }]
})
action: Some(format!("(~~)")) }]
}))
}
}
fn maybe_tuple(v: Vec<TypeRef>) -> TypeRef {
if v.len() == 1 {
v.into_iter().next().unwrap()
} else {
TypeRef::Tuple(v)
}
}

View File

@ -25,7 +25,7 @@ grammar Foo {
~v:`(~\"Id\" \",\")`* ~e:\"Id\"? =>
v.into_iter().chain(e.into_iter()).collect();
`(~\"Id\" \",\")` = ~\"Id\" \",\";
`(~\"Id\" \",\")`: `\"Id\"` = ~\"Id\" \",\" => (~~);
}
").unwrap();

View File

@ -1,5 +1,5 @@
use intern::InternedString;
use grammar::parse_tree::{Alternative, Symbol};
use grammar::parse_tree::{Alternative, ExprSymbol, Symbol};
#[derive(Debug)]
pub enum AlternativeAction<'a> {
@ -19,36 +19,36 @@ pub fn analyze_action<'a>(alt: &'a Alternative) -> AlternativeAction<'a> {
return AlternativeAction::User(code);
}
AlternativeAction::Default(analyze_symbols(alt))
AlternativeAction::Default(analyze_expr(&alt.expr))
}
pub fn analyze_symbols<'a>(alt: &'a Alternative) -> Symbols<'a> {
pub fn analyze_expr<'a>(expr: &'a ExprSymbol) -> Symbols<'a> {
// First look for named symbols.
let named_symbols: Vec<_> =
alt.expr.symbols
.iter()
.filter_map(|sym| match *sym {
Symbol::Name(id, ref sub) => Some((id, &**sub)),
_ => None,
})
.collect();
expr.symbols
.iter()
.filter_map(|sym| match *sym {
Symbol::Name(id, ref sub) => Some((id, &**sub)),
_ => None,
})
.collect();
if !named_symbols.is_empty() {
return Symbols::Named(named_symbols);
}
// Otherwise, make a tuple of the items they chose with a `~`.
let chosen_symbol_types: Vec<_> =
alt.expr.symbols
.iter()
.filter_map(|sym| match *sym {
Symbol::Choose(..) => Some(sym),
_ => None,
})
.collect();
expr.symbols
.iter()
.filter_map(|sym| match *sym {
Symbol::Choose(ref sub) => Some(&**sub),
_ => None,
})
.collect();
if !chosen_symbol_types.is_empty() {
return Symbols::Anon(chosen_symbol_types);
}
// If they didn't choose anything with a `~`, make a tuple of everything.
Symbols::Anon(alt.expr.symbols.iter().collect())
Symbols::Anon(expr.symbols.iter().collect())
}

View File

@ -2,7 +2,6 @@ use intern::intern;
use parser;
use normalize::macro_expand::expand_macros;
use normalize::tyinfer::infer_types;
use grammar::parse_tree::TypeRef;
use grammar::repr::TypeRepr;
fn type_repr(s: &str) -> TypeRepr {

View File

@ -260,7 +260,7 @@ impl<'input> rusty_peg::Symbol<'input,Parser<'input>> for CODE {
offset += 1; // move to next byte
}
let regex_str = &input.text[input.offset + 1 .. offset - 1];
let regex_str = &input.text[input.offset .. offset];
let output = rusty_peg::Input { text: input.text, offset: offset };
return Ok((output, regex_str.to_string()));
}