Various bits of cleanup; add some routines to compute type repr

from parse-tree given types table
This commit is contained in:
Niko Matsakis 2015-06-17 06:16:44 -04:00
parent 9200285d49
commit cc155debd7
5 changed files with 53 additions and 29 deletions

View File

@ -60,7 +60,7 @@ grammar Type<'input, T> {
*/
use intern::{intern, InternedString};
use grammar::repr::TypeRepr;
use grammar::repr::{Types, TypeRepr};
use std::fmt::{Display, Formatter, Error};
use util::Sep;
@ -222,6 +222,20 @@ impl Symbol {
pub fn canonical_form(&self) -> String {
format!("{}", self)
}
pub fn type_repr(&self, types: &Types) -> TypeRepr {
match *self {
Symbol::Terminal(_) => types.terminal_type().clone(),
Symbol::Nonterminal(id) => types.nt_type(id).unwrap().clone(),
Symbol::Choose(ref s) => s.type_repr(types),
Symbol::Name(_, ref s) => s.type_repr(types),
Symbol::Repeat(ref r) => r.op.type_repr(r.symbol.type_repr(types)),
Symbol::Expr(..) | Symbol::Macro(..) => {
unreachable!("symbol {} should have been expanded away", self)
}
}
}
}
impl Display for Symbol {
@ -326,3 +340,25 @@ impl RepeatOp {
TypeRepr::Nominal { path: path, types: vec![symbol_type] }
}
}
impl TypeRef {
// Converts a TypeRef to a TypeRepr, assuming no inference is
// required etc. This is safe for all types a user can directly
// type, but not safe for the result of expanding macros.
pub fn type_repr(&self) -> TypeRepr {
match *self {
TypeRef::Tuple(ref types) =>
TypeRepr::Tuple(types.iter().map(TypeRef::type_repr).collect()),
TypeRef::Nominal { ref path, ref types } =>
TypeRepr::Nominal { path: path.clone(),
types: types.iter().map(TypeRef::type_repr).collect() },
TypeRef::Lifetime(id) =>
TypeRepr::Lifetime(id),
TypeRef::Id(id) =>
TypeRepr::Nominal { path: vec![id],
types: vec![] },
TypeRef::OfSymbol(_) =>
unreachable!("OfSymbol produced by parser")
}
}
}

View File

@ -26,18 +26,24 @@ pub enum TypeRepr {
#[derive(Debug)]
pub struct Types {
terminal_type: TypeRepr,
nonterminal_types: HashMap<InternedString, TypeRepr>
}
impl Types {
pub fn new() -> Types {
Types { nonterminal_types: HashMap::new() }
pub fn new(terminal_type: TypeRepr) -> Types {
Types { terminal_type: terminal_type,
nonterminal_types: HashMap::new() }
}
pub fn add_type(&mut self, nt_id: InternedString, ty: TypeRepr) {
assert!(self.nonterminal_types.insert(nt_id, ty).is_none());
}
pub fn terminal_type(&self) -> &TypeRepr {
&self.terminal_type
}
pub fn nt_type(&self, nt_id: InternedString) -> Option<&TypeRepr> {
self.nonterminal_types.get(&nt_id)
}

View File

@ -42,7 +42,8 @@ mod macro_expand;
// Computes types where the user omitted them (or from macro
// byproducts).
//
// AFTER THIS POINT: All explicit types, no `OfSymbol` types.
// AFTER THIS POINT: there is a separate `repr::Types` table
// providing all nonterminals with an explicit type.
mod tyinfer;
// Synthesizes action code for all nonterminals.

View File

@ -16,7 +16,6 @@ pub fn infer_types(grammar: &Grammar) -> NormResult<Types> {
}
struct TypeInferencer<'grammar> {
token_type: &'grammar TypeRef,
stack: Vec<InternedString>,
nonterminals: HashMap<InternedString, NT<'grammar>>,
types: Types,
@ -29,7 +28,7 @@ struct NT<'grammar> {
alternatives: &'grammar Vec<Alternative>,
}
fn extract_token_type(grammar: &Grammar) -> NormResult<&TypeRef> {
fn extract_token_type(grammar: &Grammar) -> NormResult<TypeRepr> {
let mut token_types =
grammar.items
.iter()
@ -50,7 +49,7 @@ fn extract_token_type(grammar: &Grammar) -> NormResult<&TypeRef> {
return_err!(grammar.span, "multiple token types specified");
}
Ok(token_type)
Ok(token_type.type_repr())
}
impl<'grammar> TypeInferencer<'grammar> {
@ -73,10 +72,9 @@ impl<'grammar> TypeInferencer<'grammar> {
})
.collect();
Ok(TypeInferencer { token_type: token_type,
stack: vec![],
Ok(TypeInferencer { stack: vec![],
nonterminals: nonterminals,
types: Types::new() })
types: Types::new(token_type) })
}
fn infer_types(mut self) -> NormResult<Types> {
@ -197,7 +195,7 @@ impl<'grammar> TypeInferencer<'grammar> {
fn symbol_type(&mut self, symbol: &Symbol) -> NormResult<TypeRepr> {
match *symbol {
Symbol::Terminal(_) => self.type_ref(self.token_type),
Symbol::Terminal(_) => Ok(self.types.terminal_type().clone()),
Symbol::Nonterminal(id) => self.nonterminal_type(id),
Symbol::Choose(ref s) => self.symbol_type(s),
Symbol::Name(_, ref s) => self.symbol_type(s),

View File

@ -7,24 +7,7 @@ use grammar::repr::TypeRepr;
fn type_repr(s: &str) -> TypeRepr {
let type_ref = parser::parse_type_ref(s).unwrap();
return convert(type_ref);
fn convert(t: TypeRef) -> TypeRepr {
match t {
TypeRef::Tuple(types) =>
TypeRepr::Tuple(types.into_iter().map(convert).collect()),
TypeRef::Nominal { path, types } =>
TypeRepr::Nominal { path: path,
types: types.into_iter().map(convert).collect() },
TypeRef::Lifetime(id) =>
TypeRepr::Lifetime(id),
TypeRef::Id(id) =>
TypeRepr::Nominal { path: vec![id],
types: vec![] },
TypeRef::OfSymbol(_) =>
unreachable!("OfSymbol produced by parser")
}
}
return type_ref.type_repr();
}
fn compare(g1: &str, expected: Vec<(&'static str, &'static str)>) {