Handle records more properly in symbol table

This commit is contained in:
greg 2019-08-12 11:18:03 -07:00
parent a600d34712
commit d9eca8ffb3

View File

@ -77,11 +77,12 @@ pub enum SymbolSpec {
Func(Vec<TypeName>),
DataConstructor {
index: usize,
type_name: Rc<String>,
type_name: TypeName,
type_args: Vec<Rc<String>>,
},
RecordConstructor {
fields: HashMap<Rc<String>, Rc<String>>
members: HashMap<Rc<String>, TypeName>,
type_name: TypeName,
},
Binding
}
@ -92,7 +93,7 @@ impl fmt::Display for SymbolSpec {
match self {
Func(type_names) => write!(f, "Func({:?})", type_names),
DataConstructor { index, type_name, type_args } => write!(f, "DataConstructor(idx: {})({:?} -> {})", index, type_args, type_name),
RecordConstructor { fields: _fields } => write!(f, "RecordConstructor( <fields> )"),
RecordConstructor { type_name, ..} => write!(f, "RecordConstructor(<members> -> {})", type_name),
Binding => write!(f, "Binding"),
}
}
@ -180,7 +181,7 @@ impl SymbolTable {
fn add_type_decl(&mut self, type_name: &TypeSingletonName, body: &TypeBody, _mutable: &bool, scope_name_stack: &mut Vec<ScopeSegment>) -> Result<(), String> {
use crate::ast::{TypeIdentifier, Variant};
let TypeBody(variants) = body;
let TypeSingletonName { name, .. } = type_name;
let ref type_name = type_name.name;
//scope_name_stack.push(name.clone()); //TODO adding this makes variants scoped under their
//type name and breaks a lot of things - don't add it until importing names works
//TODO figure out why _params isn't being used here
@ -189,28 +190,44 @@ impl SymbolTable {
Variant::UnitStruct(variant_name) => {
let spec = SymbolSpec::DataConstructor {
index,
type_name: name.clone(),
type_name: type_name.clone(),
type_args: vec![],
};
self.add_new_symbol(variant_name, scope_name_stack, spec);
},
Variant::TupleStruct(variant_name, tuple_members) => {
//TODO fix the notion of a tuple type
let type_args = tuple_members.iter().map(|type_name| match type_name {
TypeIdentifier::Singleton(TypeSingletonName { name, ..}) => name.clone(),
TypeIdentifier::Tuple(_) => unimplemented!(),
}).collect();
let spec = SymbolSpec::DataConstructor {
index,
type_name: name.clone(),
type_name: type_name.clone(),
type_args
};
self.add_new_symbol(variant_name, scope_name_stack, spec);
},
//TODO if there is only one variant, and it is a record, it doesn't need to have an
//explicit name
Variant::Record { name, members: _members } => {
let fields = HashMap::new();
let spec = SymbolSpec::RecordConstructor { fields };
Variant::Record { name, members: defined_members } => {
let mut members = HashMap::new();
let mut duplicate_member_definitions = Vec::new();
for (member_name, member_type) in defined_members {
match members.entry(member_name.clone()) {
Entry::Occupied(_) => duplicate_member_definitions.push(member_name.clone()),
Entry::Vacant(v) => {
v.insert(match member_type {
TypeIdentifier::Singleton(TypeSingletonName { name, ..}) => name.clone(),
TypeIdentifier::Tuple(_) => unimplemented!(),
});
}
}
}
if duplicate_member_definitions.len() != 0 {
return Err(format!("Duplicate member(s) in definition of type {}: {:?}", type_name, duplicate_member_definitions));
}
let spec = SymbolSpec::RecordConstructor { type_name: type_name.clone(), members };
self.add_new_symbol(name, scope_name_stack, spec);
},
}