Start adding infrastructure for defining new types
This commit is contained in:
parent
cec0f35fc3
commit
209b6bba48
@ -1,20 +1,24 @@
|
|||||||
use std::collections::{hash_map::Entry, HashMap, HashSet};
|
use std::{
|
||||||
use std::fmt;
|
collections::{hash_map::Entry, HashMap, HashSet},
|
||||||
use std::rc::Rc;
|
fmt,
|
||||||
|
rc::Rc,
|
||||||
use crate::ast;
|
};
|
||||||
use crate::ast::{
|
|
||||||
Declaration, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody, TypeSingletonName,
|
use crate::{
|
||||||
Variant, VariantKind,
|
ast,
|
||||||
|
ast::{
|
||||||
|
Declaration, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody, TypeSingletonName, Variant,
|
||||||
|
VariantKind,
|
||||||
|
},
|
||||||
|
tokenizing::Location,
|
||||||
|
type_inference::{PendingType, TypeBuilder, TypeContext, TypeId, VariantBuilder},
|
||||||
};
|
};
|
||||||
use crate::tokenizing::Location;
|
|
||||||
use crate::type_inference::{TypeContext, TypeId};
|
|
||||||
|
|
||||||
mod resolver;
|
mod resolver;
|
||||||
mod symbol_trie;
|
mod symbol_trie;
|
||||||
use symbol_trie::SymbolTrie;
|
use symbol_trie::SymbolTrie;
|
||||||
mod test;
|
mod test;
|
||||||
use crate::identifier::{Id, IdStore, define_id_kind};
|
use crate::identifier::{define_id_kind, Id, IdStore};
|
||||||
|
|
||||||
define_id_kind!(DefItem);
|
define_id_kind!(DefItem);
|
||||||
pub type DefId = Id<DefItem>;
|
pub type DefId = Id<DefItem>;
|
||||||
@ -63,7 +67,6 @@ impl fmt::Display for Fqsn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO eventually this should use ItemId's to avoid String-cloning
|
//TODO eventually this should use ItemId's to avoid String-cloning
|
||||||
/// One segment within a scope.
|
/// One segment within a scope.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
|
||||||
@ -81,19 +84,9 @@ impl fmt::Display for Scope {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SymbolError {
|
pub enum SymbolError {
|
||||||
DuplicateName {
|
DuplicateName { prev_name: Fqsn, location: Location },
|
||||||
prev_name: Fqsn,
|
DuplicateVariant { type_fqsn: Fqsn, name: String },
|
||||||
location: Location,
|
DuplicateRecord { type_name: Fqsn, location: Location, member: String },
|
||||||
},
|
|
||||||
DuplicateVariant {
|
|
||||||
type_fqsn: Fqsn,
|
|
||||||
name: String,
|
|
||||||
},
|
|
||||||
DuplicateRecord {
|
|
||||||
type_name: Fqsn,
|
|
||||||
location: Location,
|
|
||||||
member: String,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -120,17 +113,13 @@ struct NameTable<K> {
|
|||||||
|
|
||||||
impl<K> NameTable<K> {
|
impl<K> NameTable<K> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self { table: HashMap::new() }
|
||||||
table: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register(&mut self, name: Fqsn, spec: NameSpec<K>) -> Result<(), SymbolError> {
|
fn register(&mut self, name: Fqsn, spec: NameSpec<K>) -> Result<(), SymbolError> {
|
||||||
match self.table.entry(name.clone()) {
|
match self.table.entry(name.clone()) {
|
||||||
Entry::Occupied(o) => Err(SymbolError::DuplicateName {
|
Entry::Occupied(o) =>
|
||||||
prev_name: name,
|
Err(SymbolError::DuplicateName { prev_name: name, location: o.get().location }),
|
||||||
location: o.get().location,
|
|
||||||
}),
|
|
||||||
Entry::Vacant(v) => {
|
Entry::Vacant(v) => {
|
||||||
v.insert(spec);
|
v.insert(spec);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -141,7 +130,6 @@ impl<K> NameTable<K> {
|
|||||||
|
|
||||||
//cf. p. 150 or so of Language Implementation Patterns
|
//cf. p. 150 or so of Language Implementation Patterns
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
|
|
||||||
def_id_store: IdStore<DefItem>,
|
def_id_store: IdStore<DefItem>,
|
||||||
|
|
||||||
/// Used for import resolution.
|
/// Used for import resolution.
|
||||||
@ -175,8 +163,11 @@ impl SymbolTable {
|
|||||||
/// The main entry point into the symbol table. This will traverse the AST in several
|
/// The main entry point into the symbol table. This will traverse the AST in several
|
||||||
/// different ways and populate subtables with information that will be used further in the
|
/// different ways and populate subtables with information that will be used further in the
|
||||||
/// compilation process.
|
/// compilation process.
|
||||||
pub fn process_ast(&mut self, ast: &ast::AST, type_context: &mut TypeContext) -> Result<(), Vec<SymbolError>> {
|
pub fn process_ast(
|
||||||
|
&mut self,
|
||||||
|
ast: &ast::AST,
|
||||||
|
type_context: &mut TypeContext,
|
||||||
|
) -> Result<(), Vec<SymbolError>> {
|
||||||
let mut runner = SymbolTableRunner { type_context, table: self };
|
let mut runner = SymbolTableRunner { type_context, table: self };
|
||||||
|
|
||||||
let errs = runner.populate_name_tables(ast);
|
let errs = runner.populate_name_tables(ast);
|
||||||
@ -193,8 +184,7 @@ impl SymbolTable {
|
|||||||
|
|
||||||
//TODO optimize this
|
//TODO optimize this
|
||||||
pub fn lookup_symbol_by_def(&self, def: &DefId) -> Option<&Symbol> {
|
pub fn lookup_symbol_by_def(&self, def: &DefId) -> Option<&Symbol> {
|
||||||
self.id_to_symbol.iter().find(|(_, sym)| sym.def_id == *def)
|
self.id_to_symbol.iter().find(|(_, sym)| sym.def_id == *def).map(|(_, sym)| sym.as_ref())
|
||||||
.map(|(_, sym)| sym.as_ref())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -210,11 +200,7 @@ impl SymbolTable {
|
|||||||
/// to a Symbol, a descriptor of what that name refers to.
|
/// to a Symbol, a descriptor of what that name refers to.
|
||||||
fn add_symbol(&mut self, id: &ItemId, fqsn: Fqsn, spec: SymbolSpec) {
|
fn add_symbol(&mut self, id: &ItemId, fqsn: Fqsn, spec: SymbolSpec) {
|
||||||
let def_id = self.def_id_store.fresh();
|
let def_id = self.def_id_store.fresh();
|
||||||
let symbol = Rc::new(Symbol {
|
let symbol = Rc::new(Symbol { fully_qualified_name: fqsn.clone(), spec, def_id });
|
||||||
fully_qualified_name: fqsn.clone(),
|
|
||||||
spec,
|
|
||||||
def_id,
|
|
||||||
});
|
|
||||||
self.symbol_trie.insert(&fqsn);
|
self.symbol_trie.insert(&fqsn);
|
||||||
self.fqsn_to_symbol.insert(fqsn, symbol.clone());
|
self.fqsn_to_symbol.insert(fqsn, symbol.clone());
|
||||||
self.id_to_symbol.insert(*id, symbol);
|
self.id_to_symbol.insert(*id, symbol);
|
||||||
@ -223,7 +209,7 @@ impl SymbolTable {
|
|||||||
|
|
||||||
struct SymbolTableRunner<'a> {
|
struct SymbolTableRunner<'a> {
|
||||||
type_context: &'a mut TypeContext,
|
type_context: &'a mut TypeContext,
|
||||||
table: &'a mut SymbolTable
|
table: &'a mut SymbolTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -269,16 +255,10 @@ impl fmt::Display for Symbol {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SymbolSpec {
|
pub enum SymbolSpec {
|
||||||
Func,
|
Func,
|
||||||
DataConstructor {
|
// The tag and arity here are *surface* tags, computed from the order in which they were
|
||||||
tag: u32,
|
// defined. The type context may create a different ordering.
|
||||||
arity: usize,
|
DataConstructor { tag: u32, arity: usize, type_id: TypeId },
|
||||||
type_id: TypeId,
|
RecordConstructor { tag: u32, members: HashMap<Rc<String>, TypeId>, type_id: TypeId },
|
||||||
},
|
|
||||||
RecordConstructor {
|
|
||||||
tag: u32,
|
|
||||||
members: HashMap<Rc<String>, TypeId>,
|
|
||||||
type_id: TypeId,
|
|
||||||
},
|
|
||||||
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
||||||
LocalVariable,
|
LocalVariable,
|
||||||
FunctionParam(u8),
|
FunctionParam(u8),
|
||||||
@ -289,22 +269,10 @@ impl fmt::Display for SymbolSpec {
|
|||||||
use self::SymbolSpec::*;
|
use self::SymbolSpec::*;
|
||||||
match self {
|
match self {
|
||||||
Func => write!(f, "Func"),
|
Func => write!(f, "Func"),
|
||||||
DataConstructor {
|
DataConstructor { tag, type_id, arity } =>
|
||||||
tag,
|
write!(f, "DataConstructor(tag: {}, arity: {}, type: {})", tag, arity, type_id),
|
||||||
type_id,
|
RecordConstructor { type_id, tag, .. } =>
|
||||||
arity,
|
write!(f, "RecordConstructor(tag: {})(<members> -> {})", tag, type_id),
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"DataConstructor(tag: {}, arity: {}, type: {})",
|
|
||||||
tag, arity, type_id
|
|
||||||
),
|
|
||||||
RecordConstructor {
|
|
||||||
type_id, tag, ..
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"RecordConstructor(tag: {})(<members> -> {})",
|
|
||||||
tag, type_id
|
|
||||||
),
|
|
||||||
GlobalBinding => write!(f, "GlobalBinding"),
|
GlobalBinding => write!(f, "GlobalBinding"),
|
||||||
LocalVariable => write!(f, "Local variable"),
|
LocalVariable => write!(f, "Local variable"),
|
||||||
FunctionParam(n) => write!(f, "Function param: {}", n),
|
FunctionParam(n) => write!(f, "Function param: {}", n),
|
||||||
@ -345,11 +313,7 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
let mut errors = vec![];
|
let mut errors = vec![];
|
||||||
|
|
||||||
for statement in statements {
|
for statement in statements {
|
||||||
let Statement {
|
let Statement { id, kind, location } = statement; //TODO I'm not sure if I need to do anything with this ID
|
||||||
id,
|
|
||||||
kind,
|
|
||||||
location,
|
|
||||||
} = statement; //TODO I'm not sure if I need to do anything with this ID
|
|
||||||
let location = *location;
|
let location = *location;
|
||||||
if let Err(err) = self.add_single_statement(id, kind, location, scope_stack, function_scope) {
|
if let Err(err) = self.add_single_statement(id, kind, location, scope_stack, function_scope) {
|
||||||
errors.push(err);
|
errors.push(err);
|
||||||
@ -370,11 +334,8 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
scope_stack.pop();
|
scope_stack.pop();
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::TypeDecl {
|
StatementKind::Declaration(Declaration::TypeDecl { name, body, mutable }) =>
|
||||||
name,
|
self.add_type_members(name, body, mutable, location, scope_stack),
|
||||||
body,
|
|
||||||
mutable,
|
|
||||||
}) => self.add_type_members(name, body, mutable, location, scope_stack),
|
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
errors.extend(recursive_errs.into_iter());
|
errors.extend(recursive_errs.into_iter());
|
||||||
@ -395,87 +356,39 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
match kind {
|
match kind {
|
||||||
StatementKind::Declaration(Declaration::FuncSig(signature)) => {
|
StatementKind::Declaration(Declaration::FuncSig(signature)) => {
|
||||||
let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone());
|
let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone());
|
||||||
self.table.fq_names.register(
|
self.table
|
||||||
fq_function.clone(),
|
.fq_names
|
||||||
NameSpec {
|
.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?;
|
||||||
location,
|
self.table.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind })?;
|
||||||
kind: NameKind::Function,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
self.table.types.register(
|
|
||||||
fq_function.clone(),
|
|
||||||
NameSpec {
|
|
||||||
location,
|
|
||||||
kind: TypeKind,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
self.add_symbol(
|
self.add_symbol(id, fq_function, SymbolSpec::Func);
|
||||||
id,
|
|
||||||
fq_function,
|
|
||||||
SymbolSpec::Func,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::FuncDecl(signature, ..)) => {
|
StatementKind::Declaration(Declaration::FuncDecl(signature, ..)) => {
|
||||||
let fn_name = &signature.name;
|
let fn_name = &signature.name;
|
||||||
let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone());
|
let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone());
|
||||||
self.table.fq_names.register(
|
self.table
|
||||||
fq_function.clone(),
|
.fq_names
|
||||||
NameSpec {
|
.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?;
|
||||||
location,
|
self.table.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind })?;
|
||||||
kind: NameKind::Function,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
self.table.types.register(
|
|
||||||
fq_function.clone(),
|
|
||||||
NameSpec {
|
|
||||||
location,
|
|
||||||
kind: TypeKind,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
self.add_symbol(
|
self.add_symbol(id, fq_function, SymbolSpec::Func);
|
||||||
id,
|
|
||||||
fq_function,
|
|
||||||
SymbolSpec::Func,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::TypeDecl { name, .. }) => {
|
StatementKind::Declaration(Declaration::TypeDecl { name, .. }) => {
|
||||||
let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone());
|
let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone());
|
||||||
self.table.types.register(
|
self.table.types.register(fq_type, NameSpec { location, kind: TypeKind })?;
|
||||||
fq_type,
|
|
||||||
NameSpec {
|
|
||||||
location,
|
|
||||||
kind: TypeKind,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::Binding { name, .. }) => {
|
StatementKind::Declaration(Declaration::Binding { name, .. }) => {
|
||||||
let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone());
|
let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone());
|
||||||
self.table.fq_names.register(
|
self.table
|
||||||
fq_binding.clone(),
|
.fq_names
|
||||||
NameSpec {
|
.register(fq_binding.clone(), NameSpec { location, kind: NameKind::Binding })?;
|
||||||
location,
|
|
||||||
kind: NameKind::Binding,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
if !function_scope {
|
if !function_scope {
|
||||||
self.add_symbol(
|
self.add_symbol(id, fq_binding, SymbolSpec::GlobalBinding);
|
||||||
id,
|
|
||||||
fq_binding,
|
|
||||||
SymbolSpec::GlobalBinding,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::Module(ModuleSpecifier { name, .. }) => {
|
StatementKind::Module(ModuleSpecifier { name, .. }) => {
|
||||||
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
|
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
|
||||||
self.table.fq_names.register(
|
self.table.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?;
|
||||||
fq_module,
|
|
||||||
NameSpec {
|
|
||||||
location,
|
|
||||||
kind: NameKind::Module,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -490,113 +403,93 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
location: Location,
|
location: Location,
|
||||||
scope_stack: &mut Vec<Scope>,
|
scope_stack: &mut Vec<Scope>,
|
||||||
) -> Vec<SymbolError> {
|
) -> Vec<SymbolError> {
|
||||||
|
|
||||||
let type_fqsn = Fqsn::from_scope_stack(scope_stack, type_name.name.clone());
|
|
||||||
|
|
||||||
let TypeBody(variants) = type_body;
|
let TypeBody(variants) = type_body;
|
||||||
let mut duplicates = HashSet::new();
|
let type_fqsn = Fqsn::from_scope_stack(scope_stack, type_name.name.clone());
|
||||||
let mut dup_errors = vec![];
|
|
||||||
|
|
||||||
for variant in variants {
|
|
||||||
if duplicates.contains(&variant.name) {
|
|
||||||
dup_errors.push(SymbolError::DuplicateVariant {
|
|
||||||
type_fqsn: type_fqsn.clone(),
|
|
||||||
name: variant.name.as_ref().to_string()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
duplicates.insert(variant.name.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dup_errors.is_empty() {
|
|
||||||
return dup_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let mut member_errors = vec![];
|
|
||||||
let mut errors = vec![];
|
|
||||||
|
|
||||||
let mut register = |id: &ItemId, fqsn: Fqsn, spec: SymbolSpec| {
|
|
||||||
let name_spec = NameSpec {
|
|
||||||
location,
|
|
||||||
kind: TypeKind,
|
|
||||||
};
|
|
||||||
if let Err(err) = self.table.types.register(fqsn.clone(), name_spec) {
|
|
||||||
errors.push(err);
|
|
||||||
} else {
|
|
||||||
self.table.add_symbol(id, fqsn, spec);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_scope = Scope::Name(type_name.name.clone());
|
let new_scope = Scope::Name(type_name.name.clone());
|
||||||
scope_stack.push(new_scope);
|
scope_stack.push(new_scope);
|
||||||
|
|
||||||
for (index, variant) in variants.iter().enumerate() {
|
// Check for duplicates before registering any types with the TypeContext
|
||||||
let tag = index as u32;
|
let mut seen_variants = HashSet::new();
|
||||||
let Variant { name, kind, id } = variant;
|
let mut errors = vec![];
|
||||||
let type_id = self.type_context.id_from_name(name.as_ref());
|
|
||||||
|
|
||||||
match kind {
|
for variant in variants {
|
||||||
VariantKind::UnitStruct => {
|
if seen_variants.contains(&variant.name) {
|
||||||
let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone());
|
errors.push(SymbolError::DuplicateVariant {
|
||||||
let spec = SymbolSpec::DataConstructor {
|
type_fqsn: type_fqsn.clone(),
|
||||||
tag,
|
name: variant.name.as_ref().to_string(),
|
||||||
arity: 0,
|
})
|
||||||
type_id,
|
}
|
||||||
};
|
seen_variants.insert(variant.name.clone());
|
||||||
register(id, fq_name, spec);
|
|
||||||
}
|
|
||||||
VariantKind::TupleStruct(items) => {
|
|
||||||
let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone());
|
|
||||||
let spec = SymbolSpec::DataConstructor {
|
|
||||||
tag,
|
|
||||||
arity: items.len(),
|
|
||||||
type_id,
|
|
||||||
};
|
|
||||||
register(id, fq_name, spec);
|
|
||||||
}
|
|
||||||
VariantKind::Record(members) => {
|
|
||||||
let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone());
|
|
||||||
|
|
||||||
let mut seen_members = HashMap::new();
|
if let VariantKind::Record(ref members) = variant.kind {
|
||||||
for (member_name, _) in members.iter() {
|
let variant_name = Fqsn::from_scope_stack(scope_stack.as_ref(), variant.name.clone());
|
||||||
match seen_members.entry(member_name.as_ref()) {
|
let mut seen_members = HashMap::new();
|
||||||
Entry::Occupied(o) => {
|
for (member_name, _) in members.iter() {
|
||||||
let location = *o.get();
|
match seen_members.entry(member_name.as_ref()) {
|
||||||
member_errors.push(SymbolError::DuplicateRecord {
|
Entry::Occupied(o) => {
|
||||||
type_name: fq_name.clone(),
|
let location = *o.get();
|
||||||
location,
|
errors.push(SymbolError::DuplicateRecord {
|
||||||
member: member_name.as_ref().to_string(),
|
type_name: variant_name.clone(),
|
||||||
});
|
location,
|
||||||
}
|
member: member_name.as_ref().to_string(),
|
||||||
//TODO eventually this should track meaningful locations
|
});
|
||||||
Entry::Vacant(v) => {
|
}
|
||||||
v.insert(Location::default());
|
//TODO eventually this should track meaningful locations
|
||||||
}
|
Entry::Vacant(v) => {
|
||||||
|
v.insert(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let spec = SymbolSpec::RecordConstructor {
|
|
||||||
tag,
|
|
||||||
type_id,
|
|
||||||
members: members
|
|
||||||
.iter()
|
|
||||||
.map(|(member_name, _type_identifier)| {
|
|
||||||
(
|
|
||||||
member_name.clone(),
|
|
||||||
self.type_context.id_from_name("DUMMY_TYPE_ID")
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
register(id, fq_name, spec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut type_builder = TypeBuilder::new(type_name.name.as_ref());
|
||||||
|
|
||||||
|
for variant in variants.iter() {
|
||||||
|
let Variant { name, kind, id: _ } = variant;
|
||||||
|
|
||||||
|
//TODO the order in which things get added to variant_builder determines the sematnics
|
||||||
|
//of `tag` later
|
||||||
|
let mut variant_builder = VariantBuilder::new(name.as_ref());
|
||||||
|
match kind {
|
||||||
|
VariantKind::UnitStruct => (),
|
||||||
|
VariantKind::TupleStruct(items) =>
|
||||||
|
for type_identifier in items {
|
||||||
|
let pending: PendingType = type_identifier.into();
|
||||||
|
variant_builder.add_member(pending);
|
||||||
|
},
|
||||||
|
VariantKind::Record(members) =>
|
||||||
|
for (field_name, type_identifier) in members.iter() {
|
||||||
|
let pending: PendingType = type_identifier.into();
|
||||||
|
variant_builder.add_record_member(field_name.as_ref(), pending);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
type_builder.add_variant(variant_builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
let type_id = self.type_context.register_type(type_builder);
|
||||||
|
|
||||||
|
for (index, variant) in variants.iter().enumerate() {
|
||||||
|
let Variant { name, kind, id } = variant;
|
||||||
|
let fqsn = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone());
|
||||||
|
let spec = match kind {
|
||||||
|
VariantKind::UnitStruct =>
|
||||||
|
SymbolSpec::DataConstructor { tag: index as u32, arity: 0, type_id },
|
||||||
|
VariantKind::TupleStruct(items) =>
|
||||||
|
SymbolSpec::DataConstructor { tag: index as u32, arity: items.len(), type_id },
|
||||||
|
VariantKind::Record(..) =>
|
||||||
|
SymbolSpec::RecordConstructor { tag: index as u32, members: HashMap::new(), type_id },
|
||||||
|
};
|
||||||
|
println!("Adding symbol {}", fqsn);
|
||||||
|
self.table.add_symbol(id, fqsn, spec);
|
||||||
|
}
|
||||||
|
|
||||||
scope_stack.pop();
|
scope_stack.pop();
|
||||||
errors.extend(member_errors.into_iter());
|
vec![]
|
||||||
errors
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::{
|
||||||
use crate::symbol_table::{Fqsn, Scope, SymbolTable, SymbolSpec};
|
ast::*,
|
||||||
use crate::util::ScopeStack;
|
symbol_table::{Fqsn, Scope, SymbolSpec, SymbolTable},
|
||||||
|
util::ScopeStack,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum NameType {
|
enum NameType {
|
||||||
@ -14,9 +16,7 @@ enum NameType {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ScopeType {
|
enum ScopeType {
|
||||||
Function {
|
Function { name: Rc<String> },
|
||||||
name: Rc<String>
|
|
||||||
},
|
|
||||||
Lambda,
|
Lambda,
|
||||||
PatternMatch,
|
PatternMatch,
|
||||||
//TODO add some notion of a let-like scope?
|
//TODO add some notion of a let-like scope?
|
||||||
@ -32,17 +32,13 @@ pub struct ScopeResolver<'a> {
|
|||||||
impl<'a> ScopeResolver<'a> {
|
impl<'a> ScopeResolver<'a> {
|
||||||
pub fn new(symbol_table: &'a mut SymbolTable) -> Self {
|
pub fn new(symbol_table: &'a mut SymbolTable) -> Self {
|
||||||
let lexical_scopes = ScopeStack::new(None);
|
let lexical_scopes = ScopeStack::new(None);
|
||||||
Self {
|
Self { symbol_table, lexical_scopes }
|
||||||
symbol_table,
|
|
||||||
lexical_scopes,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&mut self, ast: &AST) {
|
pub fn resolve(&mut self, ast: &AST) {
|
||||||
walk_ast(self, ast);
|
walk_ast(self, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn lookup_name_in_scope(&self, sym_name: &QualifiedName) -> Fqsn {
|
fn lookup_name_in_scope(&self, sym_name: &QualifiedName) -> Fqsn {
|
||||||
let QualifiedName { components, .. } = sym_name;
|
let QualifiedName { components, .. } = sym_name;
|
||||||
@ -85,7 +81,7 @@ impl<'a> ScopeResolver<'a> {
|
|||||||
if let Some(symbol) = symbol {
|
if let Some(symbol) = symbol {
|
||||||
self.symbol_table.id_to_symbol.insert(*id, symbol.clone());
|
self.symbol_table.id_to_symbol.insert(*id, symbol.clone());
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Some(NameType::Param(n)) => {
|
Some(NameType::Param(n)) => {
|
||||||
let spec = SymbolSpec::FunctionParam(*n);
|
let spec = SymbolSpec::FunctionParam(*n);
|
||||||
//TODO need to come up with a better solution for local variable FQSNs
|
//TODO need to come up with a better solution for local variable FQSNs
|
||||||
@ -98,7 +94,7 @@ impl<'a> ScopeResolver<'a> {
|
|||||||
if let Some(symbol) = symbol {
|
if let Some(symbol) = symbol {
|
||||||
self.symbol_table.id_to_symbol.insert(*id, symbol);
|
self.symbol_table.id_to_symbol.insert(*id, symbol);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
//TODO see if I can reduce this duplicate code
|
//TODO see if I can reduce this duplicate code
|
||||||
let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] };
|
let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] };
|
||||||
@ -123,38 +119,23 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
// FQSNs map to a Symbol (or this is an error), Symbols have a DefId. So for every
|
// FQSNs map to a Symbol (or this is an error), Symbols have a DefId. So for every
|
||||||
// name we import, we map a local name (a string) to a NameType::ImportedDefinition(DefId).
|
// name we import, we map a local name (a string) to a NameType::ImportedDefinition(DefId).
|
||||||
fn import(&mut self, import_spec: &ImportSpecifier) -> Recursion {
|
fn import(&mut self, import_spec: &ImportSpecifier) -> Recursion {
|
||||||
let ImportSpecifier {
|
let ImportSpecifier { ref path_components, ref imported_names, .. } = &import_spec;
|
||||||
ref path_components,
|
|
||||||
ref imported_names,
|
|
||||||
..
|
|
||||||
} = &import_spec;
|
|
||||||
match imported_names {
|
match imported_names {
|
||||||
ImportedNames::All => {
|
ImportedNames::All => {
|
||||||
let prefix = Fqsn {
|
let prefix =
|
||||||
scopes: path_components
|
Fqsn { scopes: path_components.iter().map(|c| Scope::Name(c.clone())).collect() };
|
||||||
.iter()
|
|
||||||
.map(|c| Scope::Name(c.clone()))
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
let members = self.symbol_table.symbol_trie.get_children(&prefix);
|
let members = self.symbol_table.symbol_trie.get_children(&prefix);
|
||||||
for fqsn in members.into_iter() {
|
for fqsn in members.into_iter() {
|
||||||
self.lexical_scopes.insert( fqsn.local_name(), NameType::Import(fqsn));
|
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImportedNames::LastOfPath => {
|
ImportedNames::LastOfPath => {
|
||||||
let fqsn = Fqsn {
|
let fqsn = Fqsn { scopes: path_components.iter().map(|c| Scope::Name(c.clone())).collect() };
|
||||||
scopes: path_components
|
|
||||||
.iter()
|
|
||||||
.map(|c| Scope::Name(c.clone()))
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
|
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
|
||||||
}
|
}
|
||||||
ImportedNames::List(ref names) => {
|
ImportedNames::List(ref names) => {
|
||||||
let fqsn_prefix: Vec<Scope> = path_components
|
let fqsn_prefix: Vec<Scope> =
|
||||||
.iter()
|
path_components.iter().map(|c| Scope::Name(c.clone())).collect();
|
||||||
.map(|c| Scope::Name(c.clone()))
|
|
||||||
.collect();
|
|
||||||
for name in names.iter() {
|
for name in names.iter() {
|
||||||
let mut scopes = fqsn_prefix.clone();
|
let mut scopes = fqsn_prefix.clone();
|
||||||
scopes.push(Scope::Name(name.clone()));
|
scopes.push(Scope::Name(name.clone()));
|
||||||
@ -170,23 +151,22 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
let cur_function_name = match self.lexical_scopes.get_name() {
|
let cur_function_name = match self.lexical_scopes.get_name() {
|
||||||
//TODO this needs to be a fqsn
|
//TODO this needs to be a fqsn
|
||||||
Some(ScopeType::Function { name }) => Some(name.clone()),
|
Some(ScopeType::Function { name }) => Some(name.clone()),
|
||||||
_ => None
|
_ => None,
|
||||||
};
|
};
|
||||||
match declaration {
|
match declaration {
|
||||||
Declaration::FuncDecl(signature, block) => {
|
Declaration::FuncDecl(signature, block) => {
|
||||||
let param_names = signature.params.iter().map(|param| param.name.clone());
|
let param_names = signature.params.iter().map(|param| param.name.clone());
|
||||||
//TODO I'm 90% sure this is right, until I get to closures
|
//TODO I'm 90% sure this is right, until I get to closures
|
||||||
//let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() }));
|
//let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() }));
|
||||||
let mut new_scope = ScopeStack::new(Some(ScopeType::Function { name: signature.name.clone() }));
|
let mut new_scope =
|
||||||
|
ScopeStack::new(Some(ScopeType::Function { name: signature.name.clone() }));
|
||||||
|
|
||||||
for (n, param) in param_names.enumerate().into_iter() {
|
for (n, param) in param_names.enumerate().into_iter() {
|
||||||
new_scope.insert(param, NameType::Param(n as u8));
|
new_scope.insert(param, NameType::Param(n as u8));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_resolver = ScopeResolver {
|
let mut new_resolver =
|
||||||
symbol_table: self.symbol_table,
|
ScopeResolver { symbol_table: self.symbol_table, lexical_scopes: new_scope };
|
||||||
lexical_scopes: new_scope,
|
|
||||||
};
|
|
||||||
walk_block(&mut new_resolver, block);
|
walk_block(&mut new_resolver, block);
|
||||||
Recursion::Stop
|
Recursion::Stop
|
||||||
}
|
}
|
||||||
@ -199,7 +179,7 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
}
|
}
|
||||||
Recursion::Continue
|
Recursion::Continue
|
||||||
}
|
}
|
||||||
_ => Recursion::Continue
|
_ => Recursion::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,10 +188,10 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
match &expression.kind {
|
match &expression.kind {
|
||||||
Value(name) => {
|
Value(name) => {
|
||||||
self.lookup_name_in_scope(name);
|
self.lookup_name_in_scope(name);
|
||||||
},
|
}
|
||||||
NamedStruct { name, fields: _ } => {
|
NamedStruct { name, fields: _ } => {
|
||||||
self.lookup_name_in_scope(name);
|
self.lookup_name_in_scope(name);
|
||||||
},
|
}
|
||||||
Lambda { params, body, .. } => {
|
Lambda { params, body, .. } => {
|
||||||
let param_names = params.iter().map(|param| param.name.clone());
|
let param_names = params.iter().map(|param| param.name.clone());
|
||||||
//TODO need to properly handle closure scope, this is currently broken
|
//TODO need to properly handle closure scope, this is currently broken
|
||||||
@ -222,10 +202,8 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
new_scope.insert(param, NameType::Param(n as u8));
|
new_scope.insert(param, NameType::Param(n as u8));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_resolver = ScopeResolver {
|
let mut new_resolver =
|
||||||
symbol_table: self.symbol_table,
|
ScopeResolver { symbol_table: self.symbol_table, lexical_scopes: new_scope };
|
||||||
lexical_scopes: new_scope,
|
|
||||||
};
|
|
||||||
walk_block(&mut new_resolver, body);
|
walk_block(&mut new_resolver, body);
|
||||||
return Recursion::Stop;
|
return Recursion::Stop;
|
||||||
}
|
}
|
||||||
@ -235,32 +213,25 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
}
|
}
|
||||||
let mut resolver = ScopeResolver {
|
let mut resolver = ScopeResolver {
|
||||||
lexical_scopes: self.lexical_scopes.new_scope(Some(ScopeType::PatternMatch)),
|
lexical_scopes: self.lexical_scopes.new_scope(Some(ScopeType::PatternMatch)),
|
||||||
symbol_table: self.symbol_table
|
symbol_table: self.symbol_table,
|
||||||
};
|
};
|
||||||
let new_resolver = &mut resolver;
|
let new_resolver = &mut resolver;
|
||||||
|
|
||||||
match body.as_ref() {
|
match body.as_ref() {
|
||||||
IfExpressionBody::SimpleConditional {
|
IfExpressionBody::SimpleConditional { then_case, else_case } => {
|
||||||
then_case,
|
|
||||||
else_case,
|
|
||||||
} => {
|
|
||||||
walk_block(new_resolver, then_case);
|
walk_block(new_resolver, then_case);
|
||||||
if let Some(block) = else_case.as_ref() {
|
if let Some(block) = else_case.as_ref() {
|
||||||
walk_block(new_resolver, block)
|
walk_block(new_resolver, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IfExpressionBody::SimplePatternMatch {
|
IfExpressionBody::SimplePatternMatch { pattern, then_case, else_case } => {
|
||||||
pattern,
|
|
||||||
then_case,
|
|
||||||
else_case,
|
|
||||||
} => {
|
|
||||||
walk_pattern(new_resolver, pattern);
|
walk_pattern(new_resolver, pattern);
|
||||||
walk_block(new_resolver, then_case);
|
walk_block(new_resolver, then_case);
|
||||||
if let Some(block) = else_case.as_ref() {
|
if let Some(block) = else_case.as_ref() {
|
||||||
walk_block(new_resolver, block)
|
walk_block(new_resolver, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IfExpressionBody::CondList(arms) => {
|
IfExpressionBody::CondList(arms) =>
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
match arm.condition {
|
match arm.condition {
|
||||||
Condition::Pattern(ref pat) => {
|
Condition::Pattern(ref pat) => {
|
||||||
@ -278,12 +249,11 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
walk_expression(new_resolver, guard);
|
walk_expression(new_resolver, guard);
|
||||||
}
|
}
|
||||||
walk_block(new_resolver, &arm.body);
|
walk_block(new_resolver, &arm.body);
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Recursion::Stop;
|
return Recursion::Stop;
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
Recursion::Continue
|
Recursion::Continue
|
||||||
@ -308,13 +278,14 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
self.symbol_table.add_symbol(id, fqsn, SymbolSpec::LocalVariable);
|
self.symbol_table.add_symbol(id, fqsn, SymbolSpec::LocalVariable);
|
||||||
self.lexical_scopes.insert(local_name, NameType::LocalVariable(*id));
|
self.lexical_scopes.insert(local_name, NameType::LocalVariable(*id));
|
||||||
} else {
|
} else {
|
||||||
let fqsn = Fqsn { scopes: components.iter().map(|name| Scope::Name(name.clone())).collect() };
|
let fqsn =
|
||||||
|
Fqsn { scopes: components.iter().map(|name| Scope::Name(name.clone())).collect() };
|
||||||
let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn);
|
let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn);
|
||||||
if let Some(symbol) = symbol {
|
if let Some(symbol) = symbol {
|
||||||
self.symbol_table.id_to_symbol.insert(*id, symbol.clone());
|
self.symbol_table.id_to_symbol.insert(*id, symbol.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
Recursion::Continue
|
Recursion::Continue
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
use super::{Fqsn, Scope};
|
use std::{
|
||||||
|
collections::hash_map::DefaultHasher,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
use radix_trie::{Trie, TrieCommon, TrieKey};
|
use radix_trie::{Trie, TrieCommon, TrieKey};
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::{Hash, Hasher};
|
use super::{Fqsn, Scope};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SymbolTrie(Trie<Fqsn, ()>);
|
pub struct SymbolTrie(Trie<Fqsn, ()>);
|
||||||
@ -33,11 +37,7 @@ impl SymbolTrie {
|
|||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return vec![],
|
None => return vec![],
|
||||||
};
|
};
|
||||||
let output: Vec<Fqsn> = subtrie
|
let output: Vec<Fqsn> = subtrie.keys().filter(|cur_key| **cur_key != *fqsn).cloned().collect();
|
||||||
.keys()
|
|
||||||
.filter(|cur_key| **cur_key != *fqsn)
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ fn basic_symbol_table() {
|
|||||||
let (symbols, _) = add_symbols(src);
|
let (symbols, _) = add_symbols(src);
|
||||||
|
|
||||||
symbols.types.table.get(&make_fqsn(&["Option"])).unwrap();
|
symbols.types.table.get(&make_fqsn(&["Option"])).unwrap();
|
||||||
symbols.types.table.get(&make_fqsn(&["Option", "Some"])).unwrap();
|
|
||||||
symbols.types.table.get(&make_fqsn(&["Option", "None"])).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -25,7 +25,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
|
|
||||||
for statement in reduced.entrypoint.into_iter() {
|
for statement in reduced.entrypoint.into_iter() {
|
||||||
match self.statement(statement) {
|
match self.statement(statement) {
|
||||||
Ok(Some(output)) if repl => acc.push(Ok(output.to_repl())),
|
Ok(Some(output)) if repl => acc.push(Ok(output.to_repl(&self.type_context))),
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
acc.push(Err(error.msg));
|
acc.push(Err(error.msg));
|
||||||
@ -242,11 +242,11 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
}
|
}
|
||||||
/* builtin functions */
|
/* builtin functions */
|
||||||
(IOPrint, &[ref anything]) => {
|
(IOPrint, &[ref anything]) => {
|
||||||
print!("{}", anything.to_repl());
|
print!("{}", anything.to_repl(self.type_context));
|
||||||
Primitive::Tuple(vec![])
|
Primitive::Tuple(vec![])
|
||||||
}
|
}
|
||||||
(IOPrintLn, &[ref anything]) => {
|
(IOPrintLn, &[ref anything]) => {
|
||||||
print!("{}", anything.to_repl());
|
print!("{}", anything.to_repl(self.type_context));
|
||||||
Primitive::Tuple(vec![])
|
Primitive::Tuple(vec![])
|
||||||
}
|
}
|
||||||
(IOGetLine, &[]) => {
|
(IOGetLine, &[]) => {
|
||||||
|
@ -89,9 +89,9 @@ impl From<Primitive> for MemoryValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryValue {
|
impl MemoryValue {
|
||||||
fn to_repl(&self) -> String {
|
fn to_repl(&self, type_context: &TypeContext) -> String {
|
||||||
match self {
|
match self {
|
||||||
MemoryValue::Primitive(ref prim) => prim.to_repl(),
|
MemoryValue::Primitive(ref prim) => prim.to_repl(type_context),
|
||||||
MemoryValue::Function(..) => "<function>".to_string(),
|
MemoryValue::Function(..) => "<function>".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,11 +125,16 @@ enum Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Primitive {
|
impl Primitive {
|
||||||
fn to_repl(&self) -> String {
|
fn to_repl(&self, type_context: &TypeContext) -> String {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Object { type_id, items, .. } if items.is_empty() => type_id.local_name().to_string(),
|
Primitive::Object { type_id, items, tag } if items.is_empty() =>
|
||||||
Primitive::Object { type_id, items, .. } => {
|
type_context.variant_local_name(type_id, *tag).unwrap().to_string(),
|
||||||
format!("{}{}", type_id.local_name(), paren_wrapped(items.iter().map(|item| item.to_repl())))
|
Primitive::Object { type_id, items, tag } => {
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
type_context.variant_local_name(type_id, *tag).unwrap(),
|
||||||
|
paren_wrapped(items.iter().map(|item| item.to_repl(type_context)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Primitive::Literal(lit) => match lit {
|
Primitive::Literal(lit) => match lit {
|
||||||
Literal::Nat(n) => format!("{}", n),
|
Literal::Nat(n) => format!("{}", n),
|
||||||
@ -138,7 +143,7 @@ impl Primitive {
|
|||||||
Literal::Bool(b) => format!("{}", b),
|
Literal::Bool(b) => format!("{}", b),
|
||||||
Literal::StringLit(s) => format!("\"{}\"", s),
|
Literal::StringLit(s) => format!("\"{}\"", s),
|
||||||
},
|
},
|
||||||
Primitive::Tuple(terms) => paren_wrapped(terms.iter().map(|x| x.to_repl())),
|
Primitive::Tuple(terms) => paren_wrapped(terms.iter().map(|x| x.to_repl(type_context))),
|
||||||
Primitive::Callable(..) => "<some-callable>".to_string(),
|
Primitive::Callable(..) => "<some-callable>".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,110 @@
|
|||||||
use std::{fmt, rc::Rc};
|
use std::{collections::HashMap, convert::From};
|
||||||
|
|
||||||
//TODO need to hook this into the actual typechecking system somehow
|
//use crate::symbol_table::Fqsn;
|
||||||
#[derive(Debug, Clone)]
|
use crate::{
|
||||||
pub struct TypeId {
|
ast::TypeIdentifier,
|
||||||
local_name: Rc<String>,
|
identifier::{define_id_kind, Id, IdStore},
|
||||||
|
};
|
||||||
|
|
||||||
|
define_id_kind!(TypeItem);
|
||||||
|
pub type TypeId = Id<TypeItem>;
|
||||||
|
|
||||||
|
pub struct TypeContext {
|
||||||
|
defined_types: HashMap<TypeId, DefinedType>,
|
||||||
|
type_id_store: IdStore<TypeItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TypeId {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "TypeId:{}", self.local_name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeId {
|
|
||||||
pub fn local_name(&self) -> &str {
|
|
||||||
self.local_name.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TypeContext;
|
|
||||||
|
|
||||||
impl TypeContext {
|
impl TypeContext {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self { defined_types: HashMap::new(), type_id_store: IdStore::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO flesh this out...
|
pub fn register_type(&mut self, builder: TypeBuilder) -> TypeId {
|
||||||
pub fn id_from_name(&self, name: &str) -> TypeId {
|
let type_id = self.type_id_store.fresh();
|
||||||
TypeId { local_name: Rc::new(name.to_string()) }
|
|
||||||
|
let defined = DefinedType {
|
||||||
|
name: builder.name,
|
||||||
|
//TODO come up with a canonical tag order
|
||||||
|
variants: builder.variants.into_iter().map(|builder| Variant { name: builder.name }).collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.defined_types.insert(type_id, defined);
|
||||||
|
type_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn variant_local_name(&self, type_id: &TypeId, tag: u32) -> Option<&str> {
|
||||||
|
self.defined_types
|
||||||
|
.get(type_id)
|
||||||
|
.and_then(|defined| defined.variants.get(tag as usize))
|
||||||
|
.map(|variant| variant.name.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type defined in program source code, as opposed to a builtin.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct DefinedType {
|
||||||
|
name: String,
|
||||||
|
//fqsn: Fqsn,
|
||||||
|
// the variants are in this list according to tag order
|
||||||
|
variants: Vec<Variant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Variant {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a type mentioned as a member of another type during the type registration process.
|
||||||
|
/// It may not have been registered itself in the relevant context.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct PendingType {
|
||||||
|
inner: TypeIdentifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TypeIdentifier> for PendingType {
|
||||||
|
fn from(type_identifier: &TypeIdentifier) -> Self {
|
||||||
|
Self { inner: type_identifier.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeBuilder {
|
||||||
|
name: String,
|
||||||
|
variants: Vec<VariantBuilder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeBuilder {
|
||||||
|
pub fn new(name: &str) -> Self {
|
||||||
|
Self { name: name.to_string(), variants: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_variant(&mut self, vb: VariantBuilder) {
|
||||||
|
self.variants.push(vb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VariantBuilder {
|
||||||
|
name: String,
|
||||||
|
members: Vec<VariantMember>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariantBuilder {
|
||||||
|
pub fn new(name: &str) -> Self {
|
||||||
|
Self { name: name.to_string(), members: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_member(&mut self, member_ty: PendingType) {
|
||||||
|
self.members.push(VariantMember::Pending(member_ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can't call this and `add_member` on the same fn, there should be a runtime error when
|
||||||
|
// that's detected.
|
||||||
|
pub fn add_record_member(&mut self, name: &str, ty: PendingType) {
|
||||||
|
self.members.push(VariantMember::KeyVal(name.to_string(), ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VariantMember {
|
||||||
|
Pending(PendingType),
|
||||||
|
KeyVal(String, PendingType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
Loading…
Reference in New Issue
Block a user