From b940c0fab846b5ab6b62f63e1c675fd5a0c53967 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Jun 2015 06:20:47 -0400 Subject: [PATCH] Start writing type inferencer, but adding spans broke our tests --- src/grammar/parse_tree.rs | 22 +++++++ src/normalize/macro_expand/mod.rs | 9 ++- src/normalize/mod.rs | 19 +++--- src/normalize/tyinfer.rs | 101 ++++++++++++++++++++++++++++++ src/parser/mod.rs | 15 +++-- 5 files changed, 150 insertions(+), 16 deletions(-) create mode 100644 src/normalize/tyinfer.rs diff --git a/src/grammar/parse_tree.rs b/src/grammar/parse_tree.rs index f8b29df..9ea7157 100644 --- a/src/grammar/parse_tree.rs +++ b/src/grammar/parse_tree.rs @@ -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 } @@ -301,3 +304,22 @@ impl<'a,S:Display> Display for Sep<&'a Vec> { 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), + } + } +} diff --git a/src/normalize/macro_expand/mod.rs b/src/normalize/macro_expand/mod.rs index 415f3b4..2dc0f17 100644 --- a/src/normalize/macro_expand/mod.rs +++ b/src/normalize/macro_expand/mod.rs @@ -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 }] }) } diff --git a/src/normalize/mod.rs b/src/normalize/mod.rs index 957b59f..f91c130 100644 --- a/src/normalize/mod.rs +++ b/src/normalize/mod.rs @@ -25,24 +25,25 @@ macro_rules! return_err { // These are executed *IN ORDER*: -// Expands macros +// Expands macros and expressions // -// X = ...1 Comma ...2 +// X = ...1 Comma (X Y Z) ...2 // // to // -// X = ...1 Vec_X ...2 -// Comma_X: Vec<> = ...; +// X = ...1 `Comma` `(X Y Z)` ...2 +// `Comma_X`: Vec<> = ...; +// `(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 // diff --git a/src/normalize/tyinfer.rs b/src/normalize/tyinfer.rs new file mode 100644 index 0000000..fa7a5b8 --- /dev/null +++ b/src/normalize/tyinfer.rs @@ -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 { + { + let mut inferencer = TypeInferencer::new(&mut grammar.items); + try!(inferencer.infer_types()); + } + Ok(grammar) +} + +struct TypeInferencer<'a> { + stack: Vec, + nonterminals: HashMap>, +} + +struct NT<'a> { + type_decl: &'a mut Option, + alternatives: &'a Vec, +} + +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 = + 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 = + 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 { + loop { } + } +} + +impl<'a> NT<'a> { + fn new(data: &'a mut NonterminalData) -> NT<'a> { + NT { type_decl: &mut data.type_decl, alternatives: &data.alternatives } + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index db0cf92..f6bfff9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -64,8 +64,9 @@ rusty_peg! { ("{" "}" ";") => a; ALTERNATIVE: Alternative = - ( ";") => Alternative { - expr: ExprSymbol { symbols: s }, + ( ";" ) => 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 = ( "<" ">" ) => { @@ -124,8 +125,12 @@ rusty_peg! { ESCAPE_SYMBOL: Symbol = () => Symbol::Nonterminal(l); - EXPR_SYMBOL: Symbol = - ("(" ")") => Symbol::Expr(ExprSymbol { symbols: s }); + PAREN_SYMBOL: Symbol = + ("(" ")") => Symbol::Expr(s); + + EXPR_SYMBOL: ExprSymbol = + ( ) => ExprSymbol { span: Span(lo, hi), + symbols: s }; NAMED_SYMBOL: Symbol = ("~" ":" ) => Symbol::Name(l, Box::new(s));