mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-03-16 17:00:53 +00:00
Start writing type inferencer, but adding spans broke our tests
This commit is contained in:
parent
3d77afc278
commit
b940c0fab8
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 }]
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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
101
src/normalize/tyinfer.rs
Normal 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 }
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user