Start writing type inferencer, but adding spans broke our tests

This commit is contained in:
Niko Matsakis 2015-06-16 06:20:47 -04:00
parent 3d77afc278
commit b940c0fab8
5 changed files with 150 additions and 16 deletions

View File

@ -114,6 +114,8 @@ pub struct NonterminalData {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Alternative {
pub span: Span,
pub expr: ExprSymbol,
// if C, only legal in macros
@ -194,6 +196,7 @@ pub struct RepeatSymbol {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExprSymbol {
pub span: Span,
pub symbols: Vec<Symbol>
}
@ -301,3 +304,22 @@ impl<'a,S:Display> Display for Sep<&'a Vec<S>> {
Ok(())
}
}
impl Display for TypeRef {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
match *self {
TypeRef::Tuple(ref types) =>
write!(fmt, "({})", Sep(", ", types)),
TypeRef::Nominal { ref path, ref types } if types.len() == 0 =>
write!(fmt, "{}", Sep("::", path)),
TypeRef::Nominal { ref path, ref types } =>
write!(fmt, "{}<{}>", Sep("::", path), Sep(", ", types)),
TypeRef::Lifetime(ref s) =>
write!(fmt, "{}", s),
TypeRef::Id(ref s) =>
write!(fmt, "{}", s),
TypeRef::OfSymbol(ref s) =>
write!(fmt, "`{}`", s),
}
}
}

View File

@ -164,6 +164,7 @@ impl MacroExpander {
continue;
}
alternatives.push(Alternative {
span: msym.span,
expr: self.macro_expand_expr_symbol(&args, &alternative.expr),
condition: None,
action: alternative.action.clone(),
@ -259,7 +260,8 @@ impl MacroExpander {
expr: &ExprSymbol)
-> ExprSymbol
{
ExprSymbol { symbols: self.macro_expand_symbols(args, &expr.symbols) }
ExprSymbol { span: expr.span, // FIXME derived span
symbols: self.macro_expand_symbols(args, &expr.symbols) }
}
fn macro_expand_symbol(&self,
@ -304,7 +306,10 @@ impl MacroExpander {
name: name,
args: vec![],
type_decl: None,
alternatives: vec![Alternative { expr: expr, condition: None, action: None }]
alternatives: vec![Alternative { span: expr.span,
expr: expr,
condition: None,
action: None }]
})
}

View File

@ -25,24 +25,25 @@ macro_rules! return_err {
// These are executed *IN ORDER*:
// Expands macros
// Expands macros and expressions
//
// X = ...1 Comma<X> ...2
// X = ...1 Comma<X> (X Y Z) ...2
//
// to
//
// X = ...1 Vec_X ...2
// Comma_X: Vec<<X>> = ...;
// X = ...1 `Comma<X>` `(X Y Z)` ...2
// `Comma_X`: Vec<<X>> = ...;
// `(X Y Z)` = X Y Z;
//
// AFTER THIS POINT: No more macros, macro references, or guarded
// alternatives, though type indirections may occur.
// AFTER THIS POINT: No more macros, macro references, guarded
// alternatives, or expr symbols, though type indirections may occur.
mod macro_expand;
// Computes types where the user omitted them (or
// from macro byproducts).
// Computes types where the user omitted them (or from macro
// byproducts).
//
// AFTER THIS POINT: All explicit, simple types.
// mod tyinfer;
mod tyinfer;
// Converts
//

101
src/normalize/tyinfer.rs Normal file
View File

@ -0,0 +1,101 @@
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};
use normalize::{NormResult, NormError};
use regex::Regex;
use std::mem;
pub fn infer_types(mut grammar: Grammar) -> NormResult<Grammar> {
{
let mut inferencer = TypeInferencer::new(&mut grammar.items);
try!(inferencer.infer_types());
}
Ok(grammar)
}
struct TypeInferencer<'a> {
stack: Vec<InternedString>,
nonterminals: HashMap<InternedString, NT<'a>>,
}
struct NT<'a> {
type_decl: &'a mut Option<TypeRef>,
alternatives: &'a Vec<Alternative>,
}
impl<'a> TypeInferencer<'a> {
fn new(items: &'a mut [GrammarItem]) -> TypeInferencer<'a> {
let nonterminals =
items.into_iter()
.filter_map(|item| {
match *item {
GrammarItem::TokenType(..) =>
None,
GrammarItem::Nonterminal(ref mut data) => {
assert!(!data.is_macro_def()); // normalized away by now
Some((data.name, NT::new(data)))
}
}
})
.collect();
TypeInferencer { stack: vec![], nonterminals: nonterminals }
}
fn infer_types(&mut self) -> NormResult<()> {
let ids: Vec<InternedString> =
self.nonterminals.iter()
.filter(|&(_, nt)| nt.type_decl.is_none())
.map(|(&id, _)| id)
.collect();
for id in ids {
try!(self.infer_type_for(id));
}
Ok(())
}
fn infer_type_for(&mut self, id: InternedString) -> NormResult<()> {
let alternatives;
{
let nt = &self.nonterminals[&id];
if nt.type_decl.is_some() {
return Ok(());
}
alternatives = nt.alternatives;
}
self.stack.push(id);
let alternative_types: Vec<TypeRef> =
try!(alternatives.iter()
.map(|alt| self.compute_expr_type(&alt.expr))
.collect());
let ty0 = &alternative_types[0];
for (tyN, altN) in alternative_types[1..].iter().zip(&alternatives[1..]) {
if ty0 != tyN {
return_err!(altN.expr.span,
"type of this alternative is `{}`, \
but type of first alternative is `{}`",
tyN, ty0);
}
}
self.stack.pop().unwrap();
Ok(())
}
fn compute_expr_type(&mut self, expr: &ExprSymbol) -> NormResult<TypeRef> {
loop { }
}
}
impl<'a> NT<'a> {
fn new(data: &'a mut NonterminalData) -> NT<'a> {
NT { type_decl: &mut data.type_decl, alternatives: &data.alternatives }
}
}

View File

@ -64,8 +64,9 @@ rusty_peg! {
("{" <a:{ALTERNATIVE}> "}" ";") => a;
ALTERNATIVE: Alternative =
(<s:{SYMBOL}> <c:[IF_COND]> <a:[ACTION]> ";") => Alternative {
expr: ExprSymbol { symbols: s },
(<lo:POSL> <s:EXPR_SYMBOL> <c:[IF_COND]> <a:[ACTION]> ";" <hi:POSR>) => Alternative {
span: Span(lo, hi),
expr: s,
condition: c,
action: a
};
@ -102,7 +103,7 @@ rusty_peg! {
SYMBOL0: Symbol =
(MACRO_SYMBOL / TERMINAL_SYMBOL / NT_SYMBOL / ESCAPE_SYMBOL /
EXPR_SYMBOL / NAMED_SYMBOL / CHOSEN_SYMBOL);
PAREN_SYMBOL / NAMED_SYMBOL / CHOSEN_SYMBOL);
MACRO_SYMBOL: Symbol =
(<lo:POSL> <l:ID> "<" <m:{MACRO_ARG_START}> <n:[SYMBOL]> ">" <hi:POSR>) => {
@ -124,8 +125,12 @@ rusty_peg! {
ESCAPE_SYMBOL: Symbol =
(<l:ESCAPE>) => Symbol::Nonterminal(l);
EXPR_SYMBOL: Symbol =
("(" <s:{SYMBOL}> ")") => Symbol::Expr(ExprSymbol { symbols: s });
PAREN_SYMBOL: Symbol =
("(" <s:EXPR_SYMBOL> ")") => Symbol::Expr(s);
EXPR_SYMBOL: ExprSymbol =
(<lo:POSL> <s:{SYMBOL}> <hi:POSR>) => ExprSymbol { span: Span(lo, hi),
symbols: s };
NAMED_SYMBOL: Symbol =
("~" <l:ID> ":" <s:SYMBOL>) => Symbol::Name(l, Box::new(s));