diff --git a/crates/rue-compiler/src/compiler/expr/field_access_expr.rs b/crates/rue-compiler/src/compiler/expr/field_access_expr.rs index 0e642a2..c766217 100644 --- a/crates/rue-compiler/src/compiler/expr/field_access_expr.rs +++ b/crates/rue-compiler/src/compiler/expr/field_access_expr.rs @@ -1,9 +1,10 @@ use rue_parser::FieldAccessExpr; +use rue_typing::{deconstruct_items, Rest, Type}; use crate::{ compiler::Compiler, hir::{Hir, Op}, - value::{GuardPathItem, PairType, Rest, Type, Value}, + value::{GuardPathItem, Value}, ErrorKind, }; @@ -21,22 +22,24 @@ impl Compiler<'_> { return self.unknown(); }; - let mut new_value = match self.db.ty(old_value.type_id).clone() { - Type::Struct(struct_type) => { - if let Some((index, _, &field_type)) = - struct_type.fields.get_full(field_name.text()) - { - let mut type_id = field_type; + let mut new_value = match self.ty.get(old_value.type_id).clone() { + Type::Struct(ty) => { + let fields = deconstruct_items(self.ty, ty.type_id, ty.field_names.len(), ty.rest) + .expect("invalid struct type"); - if index == struct_type.fields.len() - 1 && struct_type.rest == Rest::Optional { - type_id = self.ty.alloc(Type::Optional(type_id)); + if let Some(index) = ty.field_names.get_index_of(field_name.text()) { + let type_id = fields[index]; + + if index == ty.field_names.len() - 1 && ty.rest == Rest::Optional { + todo!(); + // TODO: type_id = self.ty.alloc(Type::Optional(type_id)); } Value::new( self.compile_index( old_value.hir_id, index, - index == struct_type.fields.len() - 1 && struct_type.rest != Rest::Nil, + index == ty.field_names.len() - 1 && ty.rest != Rest::Nil, ), type_id, ) @@ -49,14 +52,24 @@ impl Compiler<'_> { return self.unknown(); } } - Type::EnumVariant(variant_type) => { - let fields = variant_type.fields.unwrap_or_default(); + Type::Variant(variant) => { + let field_names = variant.field_names.clone().unwrap_or_default(); + + let fields = variant + .field_names + .as_ref() + .map(|field_names| { + deconstruct_items(self.ty, variant.type_id, field_names.len(), variant.rest) + .expect("invalid struct type") + }) + .unwrap_or_default(); - if let Some((index, _, &field_type)) = fields.get_full(field_name.text()) { - let mut type_id = field_type; + if let Some(index) = field_names.get_index_of(field_name.text()) { + let type_id = fields[index]; - if index == fields.len() - 1 && variant_type.rest == Rest::Optional { - type_id = self.ty.alloc(Type::Optional(type_id)); + if index == fields.len() - 1 && variant.rest == Rest::Optional { + // TODO: type_id = self.ty.alloc(Type::Optional(type_id)); + todo!() } let fields_hir_id = self.db.alloc_hir(Hir::Op(Op::Rest, old_value.hir_id)); @@ -65,7 +78,7 @@ impl Compiler<'_> { self.compile_index( fields_hir_id, index, - index == fields.len() - 1 && variant_type.rest != Rest::Nil, + index == fields.len() - 1 && variant.rest != Rest::Nil, ), type_id, ) @@ -78,7 +91,7 @@ impl Compiler<'_> { return self.unknown(); } } - Type::Pair(PairType { first, rest }) => match field_name.text() { + Type::Pair(first, rest) => match field_name.text() { "first" => Value::new( self.db.alloc_hir(Hir::Op(Op::First, old_value.hir_id)), first, diff --git a/crates/rue-compiler/src/compiler/expr/group_expr.rs b/crates/rue-compiler/src/compiler/expr/group_expr.rs index a176058..e8245de 100644 --- a/crates/rue-compiler/src/compiler/expr/group_expr.rs +++ b/crates/rue-compiler/src/compiler/expr/group_expr.rs @@ -1,6 +1,7 @@ use rue_parser::GroupExpr; +use rue_typing::TypeId; -use crate::{compiler::Compiler, value::Value, TypeId}; +use crate::{compiler::Compiler, value::Value}; impl Compiler<'_> { pub fn compile_group_expr( diff --git a/crates/rue-compiler/src/compiler/expr/list_expr.rs b/crates/rue-compiler/src/compiler/expr/list_expr.rs index fc6e7fc..b34b94a 100644 --- a/crates/rue-compiler/src/compiler/expr/list_expr.rs +++ b/crates/rue-compiler/src/compiler/expr/list_expr.rs @@ -1,11 +1,7 @@ use rue_parser::{AstNode, ListExpr}; +use rue_typing::{Type, TypeId}; -use crate::{ - compiler::Compiler, - hir::Hir, - value::{Type, Value}, - ErrorKind, TypeId, -}; +use crate::{compiler::Compiler, hir::Hir, value::Value, ErrorKind}; impl Compiler<'_> { pub fn compile_list_expr( diff --git a/crates/rue-compiler/src/compiler/expr/literal_expr.rs b/crates/rue-compiler/src/compiler/expr/literal_expr.rs index 8872395..05dfefa 100644 --- a/crates/rue-compiler/src/compiler/expr/literal_expr.rs +++ b/crates/rue-compiler/src/compiler/expr/literal_expr.rs @@ -1,8 +1,7 @@ -use clvmr::Allocator; -use num_bigint::BigInt; use rue_parser::{LiteralExpr, SyntaxKind, SyntaxToken}; +use rue_typing::bigint_to_bytes; -use crate::{compiler::Compiler, hir::Hir, value::Value, ErrorKind}; +use crate::{compiler::Compiler, hir::Hir, value::Value}; impl Compiler<'_> { pub fn compile_literal_expr(&mut self, literal: &LiteralExpr) -> Value { @@ -39,10 +38,7 @@ impl Compiler<'_> { .parse() .expect("failed to parse integer literal"); - let atom = Self::bigint_to_bytes(bigint).unwrap_or_else(|| { - self.db.error(ErrorKind::IntegerTooLarge, int.text_range()); - Vec::new() - }); + let atom = bigint_to_bytes(bigint); // Extract the atom representation of the number. Value::new(self.db.alloc_hir(Hir::Atom(atom)), self.ty.std().int) @@ -92,15 +88,4 @@ impl Compiler<'_> { self.ty.std().bytes, ) } - - pub fn bigint_to_bytes(bigint: BigInt) -> Option> { - // Create a CLVM allocator. - let mut allocator = Allocator::new(); - - // Try to allocate the number. - let ptr = allocator.new_number(bigint).ok()?; - - // Extract the atom representation of the number. - Some(allocator.atom(ptr).as_ref().to_vec()) - } } diff --git a/crates/rue-compiler/src/compiler/expr/pair_expr.rs b/crates/rue-compiler/src/compiler/expr/pair_expr.rs index bb710b4..901319a 100644 --- a/crates/rue-compiler/src/compiler/expr/pair_expr.rs +++ b/crates/rue-compiler/src/compiler/expr/pair_expr.rs @@ -6,8 +6,8 @@ use crate::{compiler::Compiler, hir::Hir, value::Value}; impl Compiler<'_> { pub fn compile_pair_expr(&mut self, pair: &PairExpr, expected_type: Option) -> Value { // Extract the first and rest type out of the expected type. - let first = expected_type.and_then(|type_id| self.ty.pair_first(type_id)); - let rest = expected_type.and_then(|type_id| self.ty.pair_rest(type_id)); + let first = expected_type.and_then(|type_id| Some(self.ty.get_pair(type_id)?.0)); + let rest = expected_type.and_then(|type_id| Some(self.ty.get_pair(type_id)?.1)); // Compile the first expression, if present. // It's a parser error if not, so it's fine to return unknown. diff --git a/crates/rue-compiler/src/compiler/item/enum_item.rs b/crates/rue-compiler/src/compiler/item/enum_item.rs index 37216d5..aa2b579 100644 --- a/crates/rue-compiler/src/compiler/item/enum_item.rs +++ b/crates/rue-compiler/src/compiler/item/enum_item.rs @@ -4,13 +4,9 @@ use indexmap::IndexMap; use num_bigint::BigInt; use num_traits::Zero; use rue_parser::EnumItem; +use rue_typing::{construct_items, Enum, Type, TypeId, Variant}; -use crate::{ - compiler::Compiler, - hir::Hir, - value::{EnumType, EnumVariantType, Type}, - ErrorKind, TypeId, -}; +use crate::{compiler::Compiler, ErrorKind}; impl Compiler<'_> { pub fn declare_enum_item(&mut self, enum_item: &EnumItem) -> TypeId { @@ -41,30 +37,36 @@ impl Compiler<'_> { // Allocate a new type for the variant. // It has to be `Unknown` for now, since field types may not be declared yet. - let type_id = self.ty.alloc(Type::Unknown); + let variant_type_id = self.ty.alloc(Type::Unknown); // Add the variant to the enum and define the token for the variant. - variants.insert(name.to_string(), type_id); - self.db.insert_type_token(type_id, name); + variants.insert(name.to_string(), variant_type_id); + self.db.insert_type_token(variant_type_id, name); } // Allocate a new type for the enum. - let type_id = self.ty.alloc(Type::Enum(EnumType { + let enum_structure = self + .ty + .alloc(Type::Union(variants.values().copied().collect())); + + let enum_type_id = self.ty.alloc(Type::Enum(Enum { + original_type_id: None, + type_id: enum_structure, has_fields, variants, })); // Add the enum to the scope and define the token for the enum. if let Some(name) = enum_item.name() { - self.scope_mut().define_type(name.to_string(), type_id); - self.db.insert_type_token(type_id, name); + self.scope_mut().define_type(name.to_string(), enum_type_id); + self.db.insert_type_token(enum_type_id, name); } - type_id + enum_type_id } pub fn compile_enum_item(&mut self, enum_item: &EnumItem, enum_type_id: TypeId) { - let Type::Enum(enum_type) = self.db.ty(enum_type_id).clone() else { + let Type::Enum(enum_type) = self.ty.get(enum_type_id).clone() else { unreachable!(); }; @@ -132,29 +134,33 @@ impl Compiler<'_> { BigInt::zero() }; - let atom = Self::bigint_to_bytes(discriminant).unwrap_or_else(|| { - self.db.error( - ErrorKind::EnumDiscriminantTooLarge, - variant - .discriminant() - .map_or(name.text_range(), |token| token.text_range()), - ); - Vec::new() - }); - - let discriminant = self.db.alloc_hir(Hir::Atom(atom)); - // Update the variant to use the real `EnumVariant` type. - *self.db.ty_mut(variant_type_id) = Type::EnumVariant(EnumVariantType { + let discriminant_type = self.ty.alloc(Type::Value(discriminant.clone())); + + let type_id = if enum_type.has_fields { + construct_items( + self.ty, + [discriminant_type] + .into_iter() + .chain(fields.values().copied()), + rest, + ) + } else { + discriminant_type + }; + + *self.ty.get_mut(variant_type_id) = Type::Variant(Variant { + original_type_id: None, enum_type: enum_type_id, - original_type_id: variant_type_id, - fields: if variant.fields().is_some() { - Some(fields) + field_names: if variant.fields().is_some() { + Some(fields.keys().cloned().collect()) } else { None }, + type_id, rest, discriminant, + generic_types: Vec::new(), }); self.type_definition_stack.pop().unwrap(); diff --git a/crates/rue-compiler/src/compiler/item/function_item.rs b/crates/rue-compiler/src/compiler/item/function_item.rs index 7648e6e..aa03ab8 100644 --- a/crates/rue-compiler/src/compiler/item/function_item.rs +++ b/crates/rue-compiler/src/compiler/item/function_item.rs @@ -1,11 +1,11 @@ use rue_parser::{AstNode, FunctionItem}; +use rue_typing::{construct_items, Callable, Rest, Type}; use crate::{ compiler::Compiler, hir::Hir, scope::Scope, symbol::{Function, Symbol}, - value::{FunctionType, Rest, Type}, ErrorKind, SymbolId, }; @@ -49,6 +49,7 @@ impl Compiler<'_> { } let mut param_types = Vec::new(); + let mut param_names = Vec::new(); let mut rest = Rest::Nil; let params = function_item.params(); @@ -73,7 +74,8 @@ impl Compiler<'_> { *self.db.symbol_mut(symbol_id) = Symbol::Parameter(if param.optional().is_some() { // If the parameter is optional, wrap the type in a possibly undefined type. // This prevents referencing the parameter until it's checked for undefined. - self.ty.alloc(Type::Optional(type_id)) + // TODO: self.ty.alloc(Type::Optional(type_id)) + todo!() } else { // Otherwise, just use the type. type_id @@ -88,8 +90,11 @@ impl Compiler<'_> { ); } + param_names.push(name.to_string()); self.scope_mut().define_symbol(name.to_string(), symbol_id); self.db.insert_symbol_token(symbol_id, name); + } else { + param_names.push(format!("#{}", i)); } // Check if it's a spread or optional parameter. @@ -133,11 +138,13 @@ impl Compiler<'_> { let hir_id = self.db.alloc_hir(Hir::Unknown); // Create the function's type. - let ty = FunctionType { - generic_types, - param_types, - rest, + let ty = Callable { + original_type_id: None, + parameter_names: param_names.into_iter().collect(), + parameters: construct_items(self.ty, param_types.into_iter(), rest), return_type, + rest, + generic_types, }; // Update the symbol with the function. diff --git a/crates/rue-compiler/src/compiler/item/struct_item.rs b/crates/rue-compiler/src/compiler/item/struct_item.rs index c6bdfda..bcca263 100644 --- a/crates/rue-compiler/src/compiler/item/struct_item.rs +++ b/crates/rue-compiler/src/compiler/item/struct_item.rs @@ -1,11 +1,8 @@ use indexmap::IndexMap; use rue_parser::{AstNode, StructField, StructItem}; +use rue_typing::{construct_items, Rest, Struct, Type, TypeId}; -use crate::{ - compiler::Compiler, - value::{Rest, StructType, Type}, - ErrorKind, TypeId, -}; +use crate::{compiler::Compiler, ErrorKind}; impl Compiler<'_> { /// Define a type for a struct in the current scope, but leave it as unknown for now. @@ -19,14 +16,20 @@ impl Compiler<'_> { } /// Compile and resolve a struct type. - pub fn compile_struct_item(&mut self, struct_item: &StructItem, type_id: TypeId) { - self.type_definition_stack.push(type_id); + pub fn compile_struct_item(&mut self, struct_item: &StructItem, struct_type_id: TypeId) { + self.type_definition_stack.push(struct_type_id); + let (fields, rest) = self.compile_struct_fields(struct_item.fields()); - *self.db.ty_mut(type_id) = Type::Struct(StructType { - original_type_id: type_id, - fields, + let type_id = construct_items(self.ty, fields.values().copied(), rest); + + *self.ty.get_mut(struct_type_id) = Type::Struct(Struct { + original_type_id: None, + field_names: fields.keys().cloned().collect(), + type_id, rest, + generic_types: Vec::new(), }); + self.type_definition_stack.pop().unwrap(); } diff --git a/crates/rue-compiler/src/compiler/stmt/if_stmt.rs b/crates/rue-compiler/src/compiler/stmt/if_stmt.rs index c58c5ac..d1af5c8 100644 --- a/crates/rue-compiler/src/compiler/stmt/if_stmt.rs +++ b/crates/rue-compiler/src/compiler/stmt/if_stmt.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; use rue_parser::{AstNode, IfStmt}; +use rue_typing::TypeId; use crate::{ compiler::{block::BlockTerminator, Compiler}, scope::Scope, value::{GuardPath, TypeOverride}, - ErrorKind, HirId, TypeId, + ErrorKind, HirId, }; impl Compiler<'_> { diff --git a/crates/rue-compiler/src/compiler/ty/function_type.rs b/crates/rue-compiler/src/compiler/ty/function_type.rs index 2d42814..47dbfbb 100644 --- a/crates/rue-compiler/src/compiler/ty/function_type.rs +++ b/crates/rue-compiler/src/compiler/ty/function_type.rs @@ -1,6 +1,6 @@ use indexmap::IndexSet; use rue_parser::{AstNode, FunctionType as Ast}; -use rue_typing::{Callable, Rest, Type, TypeId}; +use rue_typing::{construct_items, Callable, Rest, Type, TypeId}; use crate::{compiler::Compiler, ErrorKind}; @@ -14,9 +14,6 @@ impl Compiler<'_> { let len = params.len(); for (i, param) in params.into_iter().enumerate() { - // We don't actually use the names yet, - // but go ahead and check for duplicates. - // TODO: Use the name in the actual type? let name = param .name() .map(|token| token.to_string()) @@ -71,6 +68,8 @@ impl Compiler<'_> { .return_type() .map_or(self.ty.std().unknown, |ty| self.compile_type(ty)); + let parameters = construct_items(self.ty, parameters.into_iter(), rest); + // Allocate a new type for the function. // TODO: Support generic types. self.ty.alloc(Type::Callable(Callable { diff --git a/crates/rue-typing/src/semantic_types.rs b/crates/rue-typing/src/semantic_types.rs index bd8b67d..ab9d5cd 100644 --- a/crates/rue-typing/src/semantic_types.rs +++ b/crates/rue-typing/src/semantic_types.rs @@ -1,18 +1,19 @@ use std::collections::HashMap; -use indexmap::IndexSet; +use indexmap::{IndexMap, IndexSet}; use num_bigint::BigInt; use crate::{Comparison, Type, TypeId, TypeSystem}; /// The kind of ending that a list has. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum Rest { + /// This means that the list is nil-terminated. + #[default] + Nil, /// This means that there is no special terminator for the list. /// The last element is the rest value. Spread, - /// This means that the list is nil-terminated. - Nil, /// This means that the list is nil-terminated, but may contain an additional optional value. Optional, } @@ -65,7 +66,7 @@ pub struct Enum { /// Whether the enum semantically has fields. pub has_fields: bool, /// This is a map of the original variant names to their type ids. - pub variants: HashMap, + pub variants: IndexMap, } /// Represents a variant type which can optionally have fields.