Richer typeref model

This commit is contained in:
Niko Matsakis 2015-06-15 07:49:29 -04:00
parent 9e311d41d3
commit 7bf7f686d9
7 changed files with 97 additions and 128 deletions

View File

@ -5,5 +5,4 @@ use intern::{self, InternedString};
pub mod parse_tree;
pub mod repr;
pub mod token;
pub mod ty;

View File

@ -60,11 +60,10 @@ grammar Type<'input, T> {
*/
use intern::InternedString;
use grammar::ty::TypeName;
#[derive(Clone, Debug)]
pub struct Grammar {
pub type_name: TypeName,
pub type_name: TypeRef,
pub items: Vec<GrammarItem>,
}
@ -76,15 +75,36 @@ pub enum GrammarItem {
#[derive(Clone, Debug)]
pub struct TokenTypeData {
pub type_name: TypeName,
pub type_name: TypeRef,
pub conversions: Vec<(InternedString, InternedString)>,
}
#[derive(Clone, Debug)]
pub enum TypeRef {
// (T1, T2)
Tuple(Vec<TypeRef>),
// Foo<'a, 'b, T1, T2>, Foo::Bar, etc
Nominal {
path: Vec<InternedString>,
types: Vec<TypeRef>
},
// 'x ==> only should appear within nominal types, but what do we care
Lifetime(InternedString),
// Foo or Bar ==> treated specially since macros may care
Id(InternedString),
// <N> ==> type of a nonterminal, emitted by macro expansion
Nonterminal(InternedString),
}
#[derive(Clone, Debug)]
pub struct NonterminalData {
pub name: InternedString,
pub args: Vec<InternedString>, // macro arguments
pub type_decl: Option<String>,
pub type_decl: Option<TypeRef>,
pub alternatives: Vec<Alternative>
}

View File

@ -1,21 +1,21 @@
use std::collections::{HashMap};
use grammar::parse_tree::TypeRef;
use intern::InternedString;
use grammar::ty::TypeName;
#[cfg(test)]
mod test;
pub struct TokenDefinition {
// if the enum type is `foo::bar::baz<X,Y>` then:
enum_type: TypeName,
enum_type: TypeRef,
// map from a custom string, like `"("` to a variant name like LPAREN
token_map: HashMap<InternedString, InternedString>,
}
impl TokenDefinition {
pub fn new(enum_type: TypeName,
pub fn new(enum_type: TypeRef,
token_map: Vec<(InternedString, InternedString)>)
-> TokenDefinition
{
@ -25,16 +25,7 @@ impl TokenDefinition {
}
}
pub fn enum_type(&self) -> &TypeName {
pub fn enum_type(&self) -> &TypeRef {
&self.enum_type
}
pub fn match_pattern(&self, name: InternedString) -> String {
let variant_name = match self.token_map.get(&name) {
Some(&v) => v,
None => name,
};
format!("{}::{}(..)", self.enum_type.path(), variant_name)
}
}

View File

@ -1,17 +1,3 @@
use intern::intern;
use grammar::ty::TypeName;
use grammar::token::*;
fn test_token_defn() -> TokenDefinition {
TokenDefinition::new(TypeName::new(vec![intern("parser")],
intern("Token"),
vec![intern("'input")]),
vec![(intern("("), intern("LPAREN")),
(intern("R"), intern("LPAREN"))])
}
#[test]
fn test_match_pattern() {
let defn = test_token_defn();
assert_eq!(defn.match_pattern(intern("(")), "::parser::Token::LPAREN(..)");
}

View File

@ -1,51 +0,0 @@
/*!
* Simple representation of Rust types. Really only understands two
* things: named types, and tuples.
*/
use intern::{self, InternedString};
#[derive(Clone, Debug)]
pub struct TypeName {
pub module: Vec<InternedString>,
pub type_name: InternedString,
pub parameters: Vec<InternedString>,
}
impl TypeName {
pub fn new(module: Vec<InternedString>,
type_name: InternedString,
parameters: Vec<InternedString>)
-> TypeName
{
TypeName { module: module, type_name: type_name, parameters: parameters }
}
pub fn path(&self) -> String {
if self.module.is_empty() {
format!("::{}", self.type_name)
} else {
format!("::{}::{}", connect(&self.module, "::"), self.type_name)
}
}
pub fn reference(&self) -> String {
format!("{}<{}>", self.path(), connect(&self.parameters, ", "))
}
}
fn connect(strs: &[InternedString], sep: &str) -> String {
let mut buf = String::new();
intern::read(|interner| {
let mut iter = strs.iter();
if let Some(&v) = iter.next() {
buf.push_str(interner.data(v));
while let Some(&v) = iter.next() {
buf.push_str(sep);
buf.push_str(interner.data(v));
}
}
});
buf
}

View File

@ -1,5 +1,4 @@
use intern::{intern, InternedString};
use grammar::ty::TypeName;
use grammar::parse_tree::*;
use rusty_peg;
@ -10,7 +9,7 @@ rusty_peg! {
parser Parser<'input> {
// Grammar
GRAMMAR: Grammar =
("grammar" <t:TYPE_NAME> "{" <i:{GRAMMAR_ITEM}> "}") => {
("grammar" <t:TYPE_REF> "{" <i:{GRAMMAR_ITEM}> "}") => {
Grammar { type_name: t, items: i }
};
@ -18,7 +17,7 @@ rusty_peg! {
(TOKEN_TYPE / NONTERMINAL);
TOKEN_TYPE: GrammarItem =
("token" <t:TYPE_NAME> "where" "{" <c:{CONVERSION}> "}" ";") => {
("token" <t:TYPE_REF> "where" "{" <c:{CONVERSION}> "}" ";") => {
GrammarItem::TokenType(TokenTypeData {type_name: t, conversions: c })
};
@ -49,13 +48,8 @@ rusty_peg! {
NONTERMINAL_NAME_MACRO1: InternedString =
(<a:ID> ",") => a;
NONTERMINAL_TYPE: String =
(":" <s:NOT_EQ>) => s.to_string();
// FIXME this isn't really right; we should be gobbling up token
// trees here until we find an "="
NOT_EQ: &'input str =
regex("[^=]+");
NONTERMINAL_TYPE: TypeRef =
(":" <s:TYPE_REF>) => s;
ALTERNATIVES: Vec<Alternative> =
(ALTERNATIVES1 / ALTERNATIVESN);
@ -131,38 +125,53 @@ rusty_peg! {
CHOSEN_SYMBOL: Symbol =
("~" <s:SYMBOL>) => Symbol::Choose(Box::new(s));
// TypeName
// TypeRef
TYPE_NAME: TypeName =
(<prefix:{PATH_COMPONENT}> <name:ID> <suffix:PATH_SUFFIX>) => {
TypeName::new(prefix, name, suffix)
TYPE_REF: TypeRef =
(TUPLE_TYPE_REF / LIFETIME_TYPE_REF / NOMINAL_TYPE_REF);
TUPLE_TYPE_REF: TypeRef =
("(" <l:TYPE_REF_LIST> ")") => TypeRef::Tuple(l);
LIFETIME_TYPE_REF: TypeRef =
(<l:LIFETIME>) => TypeRef::Lifetime(l);
NOMINAL_TYPE_REF: TypeRef =
(<p:PATH> <a:[NOMINAL_TYPE_REF_ARGS]>) => {
if p.len() == 1 && a.is_none() {
// detect something like `Foo` and treat it specially,
// so that macro expansion can pattern match here
TypeRef::Id(p.into_iter().next().unwrap())
} else {
// otherwise, `Vec<..>` or `Foo::Bar` etc expand to
// this full path
TypeRef::Nominal { path: p, types: a.unwrap_or(vec![]) }
}
};
PATH_COMPONENT: InternedString =
NOMINAL_TYPE_REF_ARGS: Vec<TypeRef> =
("<" <l:TYPE_REF_LIST> ">") => l;
TYPE_REF_LIST: Vec<TypeRef> =
(<a:{TYPE_REF_COMMA}> <t:[TYPE_REF]>) => {
let mut a = a;
a.extend(t.into_iter());
a
};
TYPE_REF_COMMA: TypeRef =
(<t:TYPE_REF> ",") => t;
PATH: Vec<InternedString> =
(<b:{PATH_BASE}> <c:ID>) => {
let mut b = b;
b.push(c);
b
};
PATH_BASE: InternedString =
(<i:ID> "::") => i;
PATH_SUFFIX: Vec<InternedString> =
(<p:[PATH_SUFFIX_1]>) => p.unwrap_or(Vec::new());
PATH_SUFFIX_1: Vec<InternedString> =
("<" <p:PATH_PARAMETERS> ">") => p;
PATH_PARAMETERS: Vec<InternedString> =
fold(<p:PATH_PARAMETER0>,
("," <q:PATH_PARAMETER>) => { let mut p = p; p.push(q); p });
PATH_PARAMETER0: Vec<InternedString> =
(<p:PATH_PARAMETER>) => vec![p];
PATH_PARAMETER: InternedString =
(PATH_PARAMETER_TYPE / PATH_PARAMETER_LIFETIME);
PATH_PARAMETER_TYPE: InternedString =
ID;
PATH_PARAMETER_LIFETIME: InternedString =
LIFETIME;
// IDENTIFIERS, LIFETIMES
ID: InternedString =
@ -233,11 +242,6 @@ impl<'input> rusty_peg::Symbol<'input,Parser<'input>> for CODE {
}
}
pub fn parse_type_name(text: &str) -> TypeName {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&TYPE_NAME, &mut parser, text).unwrap()
}
pub fn parse_grammar(text: &str) -> Result<Grammar,rusty_peg::Error> {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&GRAMMAR, &mut parser, text)
@ -257,3 +261,8 @@ fn parse_nonterminal(text: &str) -> Result<GrammarItem,rusty_peg::Error> {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&NONTERMINAL, &mut parser, text)
}
fn parse_type_ref(text: &str) -> Result<TypeRef,rusty_peg::Error> {
let mut parser = Parser::new(());
rusty_peg::Symbol::parse_complete(&TYPE_REF, &mut parser, text)
}

View File

@ -1,7 +1,22 @@
use grammar::parse_tree::TypeRef;
#[test]
fn type_name() {
let x = super::parse_type_name("parser::Enum<'l,T>");
assert_eq!(x.reference(), "::parser::Enum<'l, T>");
fn type_ref() {
super::parse_type_ref("parser::Enum<'l,T>").unwrap();
}
#[test]
fn type_ref_tuple() {
super::parse_type_ref("(X,Y)").unwrap();
}
#[test]
fn type_ref_special_case_for_id() {
let x = super::parse_type_ref("X").unwrap();
assert!(match x {
TypeRef::Id(_) => true,
_ => false
});
}
#[test]