Have TypeContext calculate tag numbers
This commit is contained in:
parent
209b6bba48
commit
6b9ca92e00
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(clippy::enum_variant_names)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Entry, HashMap, HashSet},
|
collections::{hash_map::Entry, HashMap, HashSet},
|
||||||
fmt,
|
fmt,
|
||||||
@ -11,7 +13,7 @@ use crate::{
|
|||||||
VariantKind,
|
VariantKind,
|
||||||
},
|
},
|
||||||
tokenizing::Location,
|
tokenizing::Location,
|
||||||
type_inference::{PendingType, TypeBuilder, TypeContext, TypeId, VariantBuilder},
|
type_inference::{self, PendingType, TypeBuilder, TypeContext, TypeId, VariantBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod resolver;
|
mod resolver;
|
||||||
@ -450,11 +452,12 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
|
|
||||||
let mut type_builder = TypeBuilder::new(type_name.name.as_ref());
|
let mut type_builder = TypeBuilder::new(type_name.name.as_ref());
|
||||||
|
|
||||||
|
let mut fqsn_id_map = HashMap::new();
|
||||||
for variant in variants.iter() {
|
for variant in variants.iter() {
|
||||||
let Variant { name, kind, id: _ } = variant;
|
let Variant { name, kind, id } = variant;
|
||||||
|
|
||||||
|
fqsn_id_map.insert(Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()), id);
|
||||||
|
|
||||||
//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());
|
let mut variant_builder = VariantBuilder::new(name.as_ref());
|
||||||
match kind {
|
match kind {
|
||||||
VariantKind::UnitStruct => (),
|
VariantKind::UnitStruct => (),
|
||||||
@ -473,19 +476,21 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let type_id = self.type_context.register_type(type_builder);
|
let type_id = self.type_context.register_type(type_builder);
|
||||||
|
let type_definition = self.type_context.lookup_type(&type_id).unwrap();
|
||||||
|
|
||||||
for (index, variant) in variants.iter().enumerate() {
|
// This index is guaranteed to be the correct tag
|
||||||
let Variant { name, kind, id } = variant;
|
for (index, variant) in type_definition.variants.iter().enumerate() {
|
||||||
let fqsn = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone());
|
let fqsn = Fqsn::from_scope_stack(scope_stack.as_ref(), Rc::new(variant.name.to_string()));
|
||||||
let spec = match kind {
|
let id = fqsn_id_map.get(&fqsn).unwrap();
|
||||||
VariantKind::UnitStruct =>
|
let tag = index as u32;
|
||||||
SymbolSpec::DataConstructor { tag: index as u32, arity: 0, type_id },
|
let spec = match &variant.members {
|
||||||
VariantKind::TupleStruct(items) =>
|
type_inference::VariantMembers::Unit =>
|
||||||
SymbolSpec::DataConstructor { tag: index as u32, arity: items.len(), type_id },
|
SymbolSpec::DataConstructor { tag, arity: 0, type_id },
|
||||||
VariantKind::Record(..) =>
|
type_inference::VariantMembers::Tuple(items) =>
|
||||||
SymbolSpec::RecordConstructor { tag: index as u32, members: HashMap::new(), type_id },
|
SymbolSpec::DataConstructor { tag, arity: items.len(), type_id },
|
||||||
|
type_inference::VariantMembers::Record(..) =>
|
||||||
|
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
|
||||||
};
|
};
|
||||||
println!("Adding symbol {}", fqsn);
|
|
||||||
self.table.add_symbol(id, fqsn, spec);
|
self.table.add_symbol(id, fqsn, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::{collections::HashMap, convert::From};
|
use std::{collections::HashMap, convert::From};
|
||||||
|
|
||||||
//use crate::symbol_table::Fqsn;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::TypeIdentifier,
|
ast::TypeIdentifier,
|
||||||
identifier::{define_id_kind, Id, IdStore},
|
identifier::{define_id_kind, Id, IdStore},
|
||||||
@ -22,11 +21,51 @@ impl TypeContext {
|
|||||||
pub fn register_type(&mut self, builder: TypeBuilder) -> TypeId {
|
pub fn register_type(&mut self, builder: TypeBuilder) -> TypeId {
|
||||||
let type_id = self.type_id_store.fresh();
|
let type_id = self.type_id_store.fresh();
|
||||||
|
|
||||||
let defined = DefinedType {
|
let mut pending_variants = vec![];
|
||||||
name: builder.name,
|
for variant_builder in builder.variants.into_iter() {
|
||||||
//TODO come up with a canonical tag order
|
let members = variant_builder.members;
|
||||||
variants: builder.variants.into_iter().map(|builder| Variant { name: builder.name }).collect(),
|
if members.is_empty() {
|
||||||
};
|
pending_variants.push(Variant { name: variant_builder.name, members: VariantMembers::Unit });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let record_variant = matches!(members.get(0).unwrap(), VariantMemberBuilder::KeyVal(..));
|
||||||
|
|
||||||
|
if record_variant {
|
||||||
|
let pending_members = members
|
||||||
|
.into_iter()
|
||||||
|
.map(|var| match var {
|
||||||
|
VariantMemberBuilder::KeyVal(name, ty) => (name, ty),
|
||||||
|
_ => panic!("Compiler internal error: variant mismatch"),
|
||||||
|
});
|
||||||
|
|
||||||
|
//TODO make this mapping meaningful
|
||||||
|
let type_ids = pending_members
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, _ty_id)| (name, self.type_id_store.fresh()))
|
||||||
|
.collect();
|
||||||
|
pending_variants
|
||||||
|
.push(Variant { name: variant_builder.name, members: VariantMembers::Record(type_ids) });
|
||||||
|
} else {
|
||||||
|
let pending_members = members
|
||||||
|
.into_iter()
|
||||||
|
.map(|var| match var {
|
||||||
|
VariantMemberBuilder::Pending(pending_type) => pending_type,
|
||||||
|
_ => panic!("Compiler internal error: variant mismatch"),
|
||||||
|
});
|
||||||
|
|
||||||
|
//TODO make this mapping meaningful
|
||||||
|
let type_ids = pending_members.into_iter().map(|_ty_id| self.type_id_store.fresh()).collect();
|
||||||
|
|
||||||
|
pending_variants
|
||||||
|
.push(Variant { name: variant_builder.name, members: VariantMembers::Tuple(type_ids) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventually, I will want to have a better way of determining which numeric tag goes with
|
||||||
|
// which variant. For now, just sort them alphabetically.
|
||||||
|
pending_variants.sort_unstable_by(|a, b| a.name.cmp(&b.name));
|
||||||
|
|
||||||
|
let defined = DefinedType { name: builder.name, variants: pending_variants };
|
||||||
|
|
||||||
self.defined_types.insert(type_id, defined);
|
self.defined_types.insert(type_id, defined);
|
||||||
type_id
|
type_id
|
||||||
@ -38,24 +77,37 @@ impl TypeContext {
|
|||||||
.and_then(|defined| defined.variants.get(tag as usize))
|
.and_then(|defined| defined.variants.get(tag as usize))
|
||||||
.map(|variant| variant.name.as_ref())
|
.map(|variant| variant.name.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_type(&self, type_id: &TypeId) -> Option<&DefinedType> {
|
||||||
|
self.defined_types.get(type_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type defined in program source code, as opposed to a builtin.
|
/// A type defined in program source code, as opposed to a builtin.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct DefinedType {
|
pub struct DefinedType {
|
||||||
name: String,
|
pub name: String,
|
||||||
//fqsn: Fqsn,
|
|
||||||
// the variants are in this list according to tag order
|
// the variants are in this list according to tag order
|
||||||
variants: Vec<Variant>,
|
pub variants: Vec<Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Variant {
|
pub struct Variant {
|
||||||
name: String,
|
pub name: String,
|
||||||
|
pub members: VariantMembers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum VariantMembers {
|
||||||
|
Unit,
|
||||||
|
// Should be non-empty
|
||||||
|
Tuple(Vec<TypeId>),
|
||||||
|
Record(Vec<(String, TypeId)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a type mentioned as a member of another type during the type registration process.
|
/// 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.
|
/// It may not have been registered itself in the relevant context.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct PendingType {
|
pub struct PendingType {
|
||||||
inner: TypeIdentifier,
|
inner: TypeIdentifier,
|
||||||
}
|
}
|
||||||
@ -83,7 +135,7 @@ impl TypeBuilder {
|
|||||||
|
|
||||||
pub struct VariantBuilder {
|
pub struct VariantBuilder {
|
||||||
name: String,
|
name: String,
|
||||||
members: Vec<VariantMember>,
|
members: Vec<VariantMemberBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariantBuilder {
|
impl VariantBuilder {
|
||||||
@ -92,17 +144,18 @@ impl VariantBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_member(&mut self, member_ty: PendingType) {
|
pub fn add_member(&mut self, member_ty: PendingType) {
|
||||||
self.members.push(VariantMember::Pending(member_ty));
|
self.members.push(VariantMemberBuilder::Pending(member_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can't call this and `add_member` on the same fn, there should be a runtime error when
|
// You can't call this and `add_member` on the same fn, there should be a runtime error when
|
||||||
// that's detected.
|
// that's detected.
|
||||||
pub fn add_record_member(&mut self, name: &str, ty: PendingType) {
|
pub fn add_record_member(&mut self, name: &str, ty: PendingType) {
|
||||||
self.members.push(VariantMember::KeyVal(name.to_string(), ty));
|
self.members.push(VariantMemberBuilder::KeyVal(name.to_string(), ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum VariantMember {
|
#[derive(Debug)]
|
||||||
|
enum VariantMemberBuilder {
|
||||||
Pending(PendingType),
|
Pending(PendingType),
|
||||||
KeyVal(String, PendingType),
|
KeyVal(String, PendingType),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user