diff --git a/huia-compiler/src/function/argument.rs b/huia-compiler/src/argument.rs similarity index 100% rename from huia-compiler/src/function/argument.rs rename to huia-compiler/src/argument.rs diff --git a/huia-compiler/src/bootstrap/mod.rs b/huia-compiler/src/bootstrap/mod.rs new file mode 100644 index 0000000..eeb118a --- /dev/null +++ b/huia-compiler/src/bootstrap/mod.rs @@ -0,0 +1,11 @@ +use crate::context::Context; + +pub fn bootstrap(context: &mut Context) { + context.ensure_class(context.ident("Huia.Native.Array")); + context.ensure_class(context.ident("Huia.Native.Atom")); + context.ensure_class(context.ident("Huia.Native.Boolean")); + context.ensure_class(context.ident("Huia.Native.Float")); + context.ensure_class(context.ident("Huia.Native.Integer")); + context.ensure_class(context.ident("Huia.Native.Map")); + context.ensure_class(context.ident("Huia.Native.String")); +} diff --git a/huia-compiler/src/class/actual.rs b/huia-compiler/src/class/actual.rs deleted file mode 100644 index a752cbb..0000000 --- a/huia-compiler/src/class/actual.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::class::ClassId; -use crate::identifier::Identifier; -use std::sync::RwLock; -use wrc::WRC; - -#[derive(Debug, Clone)] -pub struct Class(WRC>); - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct ClassInner { - id: ClassId, - name: Identifier, -} - -impl ClassInner { - fn id(&self) -> ClassId { - self.id - } - - fn name(&self) -> Identifier { - self.name - } - - fn set_name(&mut self, name: Identifier) { - self.name = name - } -} - -impl Class { - pub fn new(id: ClassId, name: Identifier) -> Class { - Class(WRC::new(RwLock::new(ClassInner { id, name }))) - } - - pub fn id(&self) -> ClassId { - let class = self.0.read().unwrap(); - class.id() - } - - pub fn name(&self) -> Identifier { - let class = self.0.read().unwrap(); - class.name() - } - - pub fn set_name(&self, name: Identifier) { - let mut class = self.0.write().unwrap(); - class.set_name(name); - } -} - -impl PartialEq for Class { - fn eq(&self, other: &Class) -> bool { - self.id() == other.id() - } -} - -#[cfg(test)] -mod test { - use crate::context::Context; - - #[test] - fn set_name() { - let mut context = Context::new(); - let class = context.new_class("Marty McFly"); - assert_eq!(class.name(), context.identifiers().get("Marty McFly")); - class.set_name(context.identifiers().get("Doc Brown")); - assert_eq!(class.name(), context.identifiers().get("Doc Brown")); - } -} diff --git a/huia-compiler/src/class/class_id.rs b/huia-compiler/src/class/class_id.rs deleted file mode 100644 index 366e8a8..0000000 --- a/huia-compiler/src/class/class_id.rs +++ /dev/null @@ -1,14 +0,0 @@ -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ClassId(usize); - -impl From for usize { - fn from(data: ClassId) -> usize { - data.0 - } -} - -impl From for ClassId { - fn from(data: usize) -> ClassId { - ClassId(data) - } -} diff --git a/huia-compiler/src/class/classes.rs b/huia-compiler/src/class/classes.rs deleted file mode 100644 index 0438eb7..0000000 --- a/huia-compiler/src/class/classes.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::class::{Class, ClassId}; -use crate::identifier::Identifier; -use std::sync::RwLock; - -#[derive(Default, Debug)] -pub struct Classes(RwLock>); - -impl Classes { - pub fn new() -> Classes { - Classes(RwLock::new(Vec::new())) - } - - pub fn push(&mut self, class: Class) -> ClassId { - let mut elements = self.0.write().unwrap(); - let idx = elements.len(); - elements.push(class); - ClassId::from(idx) - } - - pub fn get(&self, idx: ClassId) -> Option { - let elements = self.0.read().unwrap(); - match elements.get(usize::from(idx)) { - Some(class) => Some(class.clone()), - None => None, - } - } - - pub fn next_id(&self) -> ClassId { - let elements = self.0.read().unwrap(); - ClassId::from(elements.len()) - } - - pub fn find(&self, name: Identifier) -> Option { - let elements = self.0.read().unwrap(); - let class = elements.iter().find(|class| class.name() == name); - match class { - Some(class) => Some(class.id()), - None => None, - } - } - - pub fn is_empty(&self) -> bool { - let elements = self.0.read().unwrap(); - elements.is_empty() - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::identifier::Identifiers; - - #[test] - fn test() { - let identifiers = Identifiers::new(); - let mut classes = Classes::new(); - - let id = classes.next_id(); - let name = identifiers.get("Marty McFly"); - let class0 = Class::new(id, name); - - let idx = classes.push(class0); - assert_eq!(usize::from(idx), 0); - - let class1 = classes.get(idx).unwrap(); - assert_eq!(class1.id(), id); - assert_eq!(class1.name(), identifiers.get("Marty McFly")); - } -} diff --git a/huia-compiler/src/class/mod.rs b/huia-compiler/src/class/mod.rs deleted file mode 100644 index 3908365..0000000 --- a/huia-compiler/src/class/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod actual; -mod class_id; -mod classes; -pub use actual::Class; -pub use class_id::ClassId; -pub use classes::Classes; diff --git a/huia-compiler/src/classes/actual.rs b/huia-compiler/src/classes/actual.rs new file mode 100644 index 0000000..fbb710d --- /dev/null +++ b/huia-compiler/src/classes/actual.rs @@ -0,0 +1,137 @@ +use crate::argument::Argument; +use crate::identifier::Identifier; +use crate::method::{Method, MethodId}; +use crate::types::TypeId; +use crate::vtable::VTable; +use std::sync::RwLock; +use wrc::WRC; + +#[derive(Debug, Clone)] +pub struct Class(WRC>); + +#[derive(Debug)] +struct ClassInner { + id: TypeId, + name: Identifier, + properties: Vec, + vtable: VTable, + impls: Vec<(TypeId, VTable)>, +} + +impl ClassInner { + fn id(&self) -> TypeId { + self.id + } + + fn name(&self) -> Identifier { + self.name + } + + fn set_name(&mut self, name: Identifier) { + self.name = name + } + + fn add_method(&mut self, method: Method) -> MethodId { + self.vtable.add_method(method) + } + + fn next_id(&self) -> MethodId { + self.vtable.next_id() + } + + fn add_property(&mut self, property: Argument) { + self.properties.push(property); + } + + fn has_property(&self, name: Identifier) -> bool { + self.properties.iter().any(|p| p.name() == name) + } + + fn implement(&mut self, tr: TypeId, vtable: VTable) { + self.impls.push((tr, vtable)); + } + + fn implements(&self, tr: TypeId) -> bool { + self.impls.iter().any(|(tr0, _)| tr0 == &tr) + } +} + +impl Class { + pub fn new(id: TypeId, name: Identifier) -> Class { + let vtable = VTable::new(); + let impls = Vec::new(); + let properties = Vec::new(); + Class(WRC::new(RwLock::new(ClassInner { + id, + name, + vtable, + properties, + impls, + }))) + } + + pub fn id(&self) -> TypeId { + let class = self.0.read().unwrap(); + class.id() + } + + pub fn name(&self) -> Identifier { + let class = self.0.read().unwrap(); + class.name() + } + + pub fn set_name(&self, name: Identifier) { + let mut class = self.0.write().unwrap(); + class.set_name(name); + } + + pub fn add_method(&self, method: Method) -> MethodId { + let mut class = self.0.write().unwrap(); + class.add_method(method) + } + + pub fn next_id(&self) -> MethodId { + let class = self.0.read().unwrap(); + class.next_id() + } + + pub fn add_property(&self, property: Argument) { + let mut class = self.0.write().unwrap(); + class.add_property(property); + } + + pub fn has_property(&self, name: Identifier) -> bool { + let class = self.0.read().unwrap(); + class.has_property(name) + } + + pub fn implement(&self, tr: TypeId, vtable: VTable) { + let mut class = self.0.write().unwrap(); + class.implement(tr, vtable); + } + + pub fn implements(&self, tr: TypeId) -> bool { + let class = self.0.read().unwrap(); + class.implements(tr) + } +} + +impl PartialEq for Class { + fn eq(&self, other: &Class) -> bool { + self.id() == other.id() + } +} + +#[cfg(test)] +mod test { + use crate::context::Context; + + #[test] + fn set_name() { + let mut context = Context::new(); + let class = context.ensure_class(context.ident("Marty McFly")); + assert_eq!(class.name(), context.ident("Marty McFly")); + class.set_name(context.ident("Doc Brown")); + assert_eq!(class.name(), context.ident("Doc Brown")); + } +} diff --git a/huia-compiler/src/classes/mod.rs b/huia-compiler/src/classes/mod.rs new file mode 100644 index 0000000..3586786 --- /dev/null +++ b/huia-compiler/src/classes/mod.rs @@ -0,0 +1,2 @@ +mod actual; +pub use actual::Class; diff --git a/huia-compiler/src/constant.rs b/huia-compiler/src/constant.rs deleted file mode 100644 index 2939bce..0000000 --- a/huia-compiler/src/constant.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::class::ClassId; -use string_interner::{StringInterner, Sym}; - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ConstantId(usize); - -impl From for usize { - fn from(data: ConstantId) -> usize { - data.0 - } -} - -impl From for ConstantId { - fn from(data: usize) -> ConstantId { - ConstantId(data) - } -} - -#[derive(Debug, Default)] -pub struct Constants { - values: Vec, - strings: StringInterner, -} - -impl Constants { - pub fn new() -> Constants { - Constants { - values: Vec::new(), - strings: StringInterner::default(), - } - } - - pub fn get(&self, id: ConstantId) -> Option<&Constant> { - match self.values.get(id.0) { - Some(constant) => Some(&constant), - None => None, - } - } - - pub fn new_i64(&mut self, class_id: ClassId, i: i64) -> ConstantId { - let value = ConstantInner::I64(i); - let constant = Constant { class_id, value }; - let id = self.values.len(); - self.values.push(constant); - ConstantId(id) - } - - pub fn get_i64(&self, id: ConstantId) -> Option { - let idx = id.0; - let constant = self.values[idx].clone(); - match constant.value { - ConstantInner::I64(i) => Some(i), - _ => None, - } - } - - pub fn new_f64(&mut self, class_id: ClassId, f: f64) -> ConstantId { - let value = ConstantInner::F64(f); - let constant = Constant { class_id, value }; - let id = self.values.len(); - self.values.push(constant); - ConstantId(id) - } - - pub fn get_f64(&self, id: ConstantId) -> Option { - let idx = id.0; - let constant = self.values[idx].clone(); - match constant.value { - ConstantInner::F64(f) => Some(f), - _ => None, - } - } - - pub fn new_string(&mut self, class_id: ClassId, s: &str) -> ConstantId { - let sym = self.strings.get_or_intern(s); - let value = ConstantInner::String(sym); - let constant = Constant { class_id, value }; - let id = self.values.len(); - self.values.push(constant); - ConstantId(id) - } - - pub fn get_string(&self, id: ConstantId) -> Option<&str> { - let idx = id.0; - let constant = self.values[idx].clone(); - match constant.value { - ConstantInner::String(s) => self.strings.resolve(s), - _ => None, - } - } - - pub fn is_empty(&self) -> bool { - self.values.is_empty() && self.strings.is_empty() - } -} - -#[derive(Debug, PartialEq, PartialOrd, Clone)] -pub struct Constant { - class_id: ClassId, - value: ConstantInner, -} - -impl Constant { - pub fn is_i64(&self) -> bool { - match self.value { - ConstantInner::I64(_) => true, - _ => false, - } - } - - pub fn is_f64(&self) -> bool { - match self.value { - ConstantInner::F64(_) => true, - _ => false, - } - } - - pub fn is_string(&self) -> bool { - match self.value { - ConstantInner::String(_) => true, - _ => false, - } - } -} - -#[derive(Debug, PartialEq, PartialOrd, Clone)] -enum ConstantInner { - I64(i64), - F64(f64), - String(Sym), -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test() { - let mut constants = Constants::new(); - assert!(constants.is_empty()); - - let class_id = ClassId::from(0); - - let i = constants.new_i64(class_id, 123); - assert!(constants.get(i).unwrap().is_i64()); - assert_eq!(constants.get_i64(i).unwrap(), 123); - - let f = constants.new_f64(class_id, 1.21); - assert!(constants.get(f).unwrap().is_f64()); - let f0 = constants.get_f64(f).unwrap() - 1.21; - assert!(f0 < std::f64::EPSILON); - - let s = constants.new_string(class_id, "Marty McFly"); - assert!(constants.get(s).unwrap().is_string()); - assert_eq!(constants.get_string(s).unwrap(), "Marty McFly"); - } -} diff --git a/huia-compiler/src/context.rs b/huia-compiler/src/context.rs index 84990e4..b608f4a 100644 --- a/huia-compiler/src/context.rs +++ b/huia-compiler/src/context.rs @@ -1,65 +1,81 @@ -use crate::class::{Class, Classes}; -use crate::constant::Constants; +use crate::classes::Class; use crate::function::Functions; -use crate::identifier::Identifiers; -use crate::r#trait::{Trait, Traits}; +use crate::identifier::{Identifier, Identifiers}; +use crate::traits::Trait; +use crate::types::{Type, TypeId, TypeTable}; #[derive(Debug, Default)] pub struct Context { - classes: Classes, - traits: Traits, + types: TypeTable, identifiers: Identifiers, - constants: Constants, functions: Functions, } impl Context { pub fn new() -> Context { Context { - classes: Classes::new(), - traits: Traits::new(), + types: TypeTable::new(), identifiers: Identifiers::new(), - constants: Constants::new(), functions: Functions::new(), } } - pub fn new_class(&mut self, name: &str) -> Class { - let name = self.identifiers.get(name); - let id = self.classes.next_id(); - let class = Class::new(id, name); - self.classes.push(class); - self.classes.get(id).unwrap() + pub fn ensure_class(&self, name: Identifier) -> Class { + match self.get_type_by_name(name) { + Some(ty) => match ty.as_class() { + Some(ty) => ty, + None => self.create_class(name), + }, + None => self.create_class(name), + } } - pub fn new_trait(&mut self, name: &str) -> Trait { - let name = self.identifiers.get(name); - let id = self.traits.next_id(); + pub fn ensure_trait(&self, name: Identifier) -> Trait { + match self.get_type_by_name(name) { + Some(ty) => match ty.as_trait() { + Some(ty) => ty, + None => self.create_trait(name), + }, + None => self.create_trait(name), + } + } + + fn create_class(&self, name: Identifier) -> Class { + let id = self.types.next_id(); + let class = Class::new(id, name); + self.types.push(class.clone()); + class + } + + fn create_trait(&self, name: Identifier) -> Trait { + let id = self.types.next_id(); let tr = Trait::new(id, name); - self.traits.push(tr); - self.traits.get(id).unwrap() + self.types.push(tr.clone()); + tr + } + + pub fn get_type(&self, id: TypeId) -> Option { + self.types.get(id) + } + + pub fn get_type_by_name(&self, name: Identifier) -> Option { + self.types.find(name) + } + + pub fn ident(&self, name: &str) -> Identifier { + self.identifiers().get(name) } pub fn is_empty(&self) -> bool { - // Traits and Classes must be empty if identifiers is empty because - // classes and traits must be initialised with identifier names. - self.identifiers.is_empty() && self.constants.is_empty() + self.identifiers.is_empty() && self.types.is_empty() } pub fn identifiers(&self) -> &Identifiers { &self.identifiers } - pub fn constants(&self) -> &Constants { - &self.constants - } - - pub fn classes(&self) -> &Classes { - &self.classes - } - - pub fn traits(&self) -> &Traits { - &self.traits + pub fn types(&self) -> &TypeTable { + &self.types } pub fn functions(&self) -> &Functions { @@ -73,16 +89,16 @@ mod test { #[test] fn new() { - let mut context = Context::new(); - let class0 = context.new_class("Marty McFly"); - let class1 = context.classes().get(class0.id()).unwrap(); + let context = Context::new(); + let class0 = context.ensure_class(context.ident("Marty McFly")); + let class1 = context.types().get(class0.id()).unwrap(); assert_eq!(class0, class1); - let tr0 = context.new_trait("Doc Brown"); - let tr1 = context.traits().get(tr0.id()).unwrap(); + let tr0 = context.ensure_trait(context.ident("Doc Brown")); + let tr1 = context.types().get(tr0.id()).unwrap(); assert_eq!(tr0, tr1); - let id = context.identifiers().get("Einstein Brown"); + let id = context.ident("Einstein Brown"); assert_eq!(context.identifiers().resolve(id).unwrap(), "Einstein Brown"); } } diff --git a/huia-compiler/src/function/actual.rs b/huia-compiler/src/function/actual.rs index 7f4c630..d7500f7 100644 --- a/huia-compiler/src/function/actual.rs +++ b/huia-compiler/src/function/actual.rs @@ -1,5 +1,4 @@ use crate::function::{Clause, ClauseId, FunctionId}; -use crate::identifier::Identifier; use std::sync::RwLock; use wrc::WRC; @@ -9,7 +8,6 @@ pub struct Function(WRC>); #[derive(Debug)] struct FunctionInner { id: FunctionId, - name: Identifier, clauses: Vec, } @@ -18,14 +16,6 @@ impl FunctionInner { self.id } - fn name(&self) -> Identifier { - self.name - } - - fn set_name(&mut self, name: Identifier) { - self.name = name - } - fn add_clause(&mut self, clause: Clause) -> ClauseId { let idx = self.clauses.len(); self.clauses.push(clause); @@ -38,9 +28,9 @@ impl FunctionInner { } impl Function { - pub fn new(id: FunctionId, name: Identifier) -> Function { + pub fn new(id: FunctionId) -> Function { let clauses = Vec::new(); - Function(WRC::new(RwLock::new(FunctionInner { id, name, clauses }))) + Function(WRC::new(RwLock::new(FunctionInner { id, clauses }))) } pub fn id(&self) -> FunctionId { @@ -48,16 +38,6 @@ impl Function { fun.id() } - pub fn name(&self) -> Identifier { - let fun = self.0.read().unwrap(); - fun.name() - } - - pub fn set_name(&self, name: Identifier) { - let mut fun = self.0.write().unwrap(); - fun.set_name(name); - } - pub fn add_clause(&self, clause: Clause) -> ClauseId { let mut fun = self.0.write().unwrap(); fun.add_clause(clause) diff --git a/huia-compiler/src/function/clause.rs b/huia-compiler/src/function/clause.rs index 0eceff8..b4755cc 100644 --- a/huia-compiler/src/function/clause.rs +++ b/huia-compiler/src/function/clause.rs @@ -1,8 +1,9 @@ -use crate::function::{Argument, ClauseId}; +use crate::argument::Argument; +use crate::function::ClauseId; use std::sync::RwLock; use wrc::WRC; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Clause(WRC>); #[derive(Debug)] diff --git a/huia-compiler/src/function/functions.rs b/huia-compiler/src/function/functions.rs index 544d1a4..e450a4c 100644 --- a/huia-compiler/src/function/functions.rs +++ b/huia-compiler/src/function/functions.rs @@ -1,5 +1,4 @@ use crate::function::{Function, FunctionId}; -use crate::identifier::Identifier; use std::sync::RwLock; #[derive(Default, Debug)] @@ -30,15 +29,6 @@ impl Functions { FunctionId::from(elements.len()) } - pub fn find(&self, name: Identifier) -> Option { - let elements = self.0.read().unwrap(); - let function = elements.iter().find(|function| function.name() == name); - match function { - Some(function) => Some(function.id()), - None => None, - } - } - pub fn is_empty(&self) -> bool { let elements = self.0.read().unwrap(); elements.is_empty() @@ -48,22 +38,18 @@ impl Functions { #[cfg(test)] mod test { use super::*; - use crate::identifier::Identifiers; #[test] fn test() { - let identifiers = Identifiers::new(); let mut functions = Functions::new(); let id = functions.next_id(); - let name = identifiers.get("Marty McFly"); - let function0 = Function::new(id, name); + let function0 = Function::new(id); let idx = functions.push(function0); assert_eq!(usize::from(idx), 0); let function1 = functions.get(idx).unwrap(); assert_eq!(function1.id(), id); - assert_eq!(function1.name(), identifiers.get("Marty McFly")); } } diff --git a/huia-compiler/src/function/mod.rs b/huia-compiler/src/function/mod.rs index ff52f99..35bfbcf 100644 --- a/huia-compiler/src/function/mod.rs +++ b/huia-compiler/src/function/mod.rs @@ -3,11 +3,9 @@ mod clause; mod clause_id; mod function_id; mod functions; -mod argument; pub use actual::Function; pub use clause::Clause; pub use clause_id::ClauseId; pub use function_id::FunctionId; pub use functions::Functions; -pub use argument::Argument; diff --git a/huia-compiler/src/instructions/mod.rs b/huia-compiler/src/instructions/mod.rs index 8b13789..c763615 100644 --- a/huia-compiler/src/instructions/mod.rs +++ b/huia-compiler/src/instructions/mod.rs @@ -1 +1,12 @@ - +pub enum Instruction { + Noop = 0, + InvokePrimitive, + Pop, + PushFalse, + PushInteger, + PushLocal, + PushSelf, + PushTrue, + Return, + SetLocal, +} diff --git a/huia-compiler/src/lib.rs b/huia-compiler/src/lib.rs index 593dab6..05b14f0 100644 --- a/huia-compiler/src/lib.rs +++ b/huia-compiler/src/lib.rs @@ -1,17 +1,25 @@ -mod class; -mod constant; +mod argument; +mod bootstrap; +mod classes; mod context; mod function; mod identifier; mod instructions; -mod property_type_map; -mod r#trait; -mod r#type; +mod method; +mod object; +mod parse_consumer; +mod scope; +mod stack; +mod traits; mod type_spec; +mod types; +mod vtable; -pub use class::{Class, ClassId}; +pub use argument::Argument; +pub use classes::Class; pub use context::Context; pub use identifier::Identifier; -pub use r#trait::{Trait, TraitId}; -pub use r#type::Type; +pub use object::Object; +pub use traits::Trait; pub use type_spec::TypeSpec; +pub use types::TypeId; diff --git a/huia-compiler/src/method/actual.rs b/huia-compiler/src/method/actual.rs new file mode 100644 index 0000000..104f5c9 --- /dev/null +++ b/huia-compiler/src/method/actual.rs @@ -0,0 +1,50 @@ +use crate::function::FunctionId; +use crate::identifier::Identifier; + +#[derive(Debug, Clone)] +pub struct Method { + name: Identifier, + function: FunctionId, + flag: Flag, +} + +#[derive(Debug, Copy, Clone)] +pub enum Flag { + Public, + Private, + Static, +} + +impl Method { + pub fn new(name: Identifier, function: FunctionId, flag: Flag) -> Method { + Method { + name, + function, + flag, + } + } + + pub fn name(&self) -> Identifier { + self.name + } + + pub fn set_name(&mut self, name: Identifier) { + self.name = name; + } + + pub fn function(&self) -> FunctionId { + self.function + } + + pub fn set_function(&mut self, function: FunctionId) { + self.function = function + } + + pub fn flag(&self) -> Flag { + self.flag + } + + pub fn set_flag(&mut self, flag: Flag) { + self.flag = flag; + } +} diff --git a/huia-compiler/src/method/method_id.rs b/huia-compiler/src/method/method_id.rs new file mode 100644 index 0000000..028f1e0 --- /dev/null +++ b/huia-compiler/src/method/method_id.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct MethodId(usize); + +impl From for usize { + fn from(data: MethodId) -> usize { + data.0 + } +} + +impl From for MethodId { + fn from(data: usize) -> MethodId { + MethodId(data) + } +} diff --git a/huia-compiler/src/method/mod.rs b/huia-compiler/src/method/mod.rs new file mode 100644 index 0000000..dc00ca3 --- /dev/null +++ b/huia-compiler/src/method/mod.rs @@ -0,0 +1,5 @@ +mod actual; +mod method_id; + +pub use actual::{Flag, Method}; +pub use method_id::MethodId; diff --git a/huia-compiler/src/object.rs b/huia-compiler/src/object.rs new file mode 100644 index 0000000..72f3fe4 --- /dev/null +++ b/huia-compiler/src/object.rs @@ -0,0 +1,94 @@ +use crate::classes::Class; +use crate::types::TypeId; +use std::hash; +use string_interner::Sym; +use wrc::WRC; + +#[derive(Debug, PartialOrd, Clone)] +pub struct Object(WRC); + +#[derive(Debug, PartialEq, PartialOrd)] +struct ObjectInner { + type_id: TypeId, + value: ObjectValue, +} + +#[derive(Debug, PartialEq, PartialOrd)] +pub enum ObjectValue { + Array(Vec), + Atom(Sym), + False, + Float(f64), + Integer(i64), + String(Sym), + True, +} + +impl From> for ObjectValue { + fn from(data: Vec) -> ObjectValue { + ObjectValue::Array(data) + } +} + +impl From for ObjectValue { + fn from(data: bool) -> ObjectValue { + if data { + ObjectValue::True + } else { + ObjectValue::False + } + } +} + +impl From for ObjectValue { + fn from(data: f64) -> ObjectValue { + ObjectValue::Float(data) + } +} + +impl From for ObjectValue { + fn from(data: i64) -> ObjectValue { + ObjectValue::Integer(data) + } +} + +impl Object { + pub fn alloc(class: Class, data: ObjectValue) -> Object { + Object(WRC::new(ObjectInner { + type_id: class.id(), + value: data, + })) + } + + pub fn type_id(&self) -> TypeId { + self.0.type_id + } +} + +impl hash::Hash for Object { + fn hash(&self, mut h: &mut H) { + self.0.type_id.hash(&mut h); + match &self.0.value { + ObjectValue::Array(objs) => { + for o in objs { + o.hash(&mut h) + } + } + ObjectValue::Atom(s) => s.hash(&mut h), + ObjectValue::False => false.hash(&mut h), + ObjectValue::Float(f) => { + let bitpattern = unsafe { std::mem::transmute::(*f) }; + bitpattern.hash(&mut h); + } + ObjectValue::Integer(i) => i.hash(&mut h), + ObjectValue::String(s) => s.hash(&mut h), + ObjectValue::True => true.hash(&mut h), + } + } +} + +impl PartialEq for Object { + fn eq(&self, other: &Object) -> bool { + self.0.type_id == other.0.type_id && self.0.value == other.0.value + } +} diff --git a/huia-compiler/src/parse_consumer/definition.rs b/huia-compiler/src/parse_consumer/definition.rs new file mode 100644 index 0000000..5dd6b46 --- /dev/null +++ b/huia-compiler/src/parse_consumer/definition.rs @@ -0,0 +1,56 @@ +use crate::argument::Argument; +use crate::context::Context; +use crate::types::TypeId; +use huia_parser::ast::{Term, Value}; + +pub fn consume(context: &mut Context, term: &Term) -> DefinitionId { + let (deftype, defname, args, body, reqs) = term.definition().unwrap(); + match deftype.value_ref().as_str() { + "type" => { + let name = context + .identifiers() + .get(defname.typename().unwrap().value_ref().as_str()); + let class = context.ensure_class(name); + for (name, term) in args { + let name = context.ident(name.value_ref()); + let mut argument = Argument::new(name); + println!("argument: {:?}", term); + class.add_property(argument); + } + DefinitionId::from(class.id()) + } + _ => panic!("Unexpected define type {:?}", deftype), + } +} + +#[derive(Debug, Copy, Clone)] +pub enum DefinitionId { + TypeId(TypeId), +} + +impl From for DefinitionId { + fn from(id: TypeId) -> DefinitionId { + DefinitionId::TypeId(id) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn class_definition() { + let mut context = Context::new(); + let terms = Term::input("type Delorean(speed: Integer)").unwrap(); + + consume(&mut context, &terms[0]); + + let class = context + .types() + .find(context.ident("Delorean")) + .unwrap() + .as_class() + .unwrap(); + assert!(class.has_property(context.ident("speed"))) + } +} diff --git a/huia-compiler/src/parse_consumer/mod.rs b/huia-compiler/src/parse_consumer/mod.rs new file mode 100644 index 0000000..3d2d29b --- /dev/null +++ b/huia-compiler/src/parse_consumer/mod.rs @@ -0,0 +1,12 @@ +use crate::argument::Argument; +use crate::context::Context; +use huia_parser::ast::{NodeType, Term, Value}; + +mod definition; + +pub fn consume(mut context: &mut Context, term: &Term) { + match term.node_type() { + NodeType::Definition => definition::consume(&mut context, term), + _ => panic!("Unexpected node {:?}", term.node_type()), + }; +} diff --git a/huia-compiler/src/property_type_map.rs b/huia-compiler/src/property_type_map.rs deleted file mode 100644 index 1d1c3b3..0000000 --- a/huia-compiler/src/property_type_map.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::identifier::Identifier; -use crate::type_spec::TypeSpec; -use std::collections::BTreeMap; - -#[derive(Debug, Default)] -pub struct PropertyTypeMap(BTreeMap); - -impl PropertyTypeMap { - pub fn new() -> PropertyTypeMap { - PropertyTypeMap(BTreeMap::new()) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn insert(&mut self, name: Identifier, ts: TypeSpec) { - self.0.insert(name, ts); - } - - pub fn has_property(&self, name: Identifier) -> bool { - self.0.contains_key(&name) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::context::Context; - - #[test] - fn test() { - let mut context = Context::new(); - - let mut ptm = PropertyTypeMap::new(); - assert!(ptm.is_empty()); - - let pname = context.identifiers().get("character"); - let ptype = TypeSpec::from(context.new_trait("Character")); - ptm.insert(pname, ptype); - - assert!(ptm.has_property(pname)); - } -} diff --git a/huia-compiler/src/scope.rs b/huia-compiler/src/scope.rs new file mode 100644 index 0000000..a82b2f6 --- /dev/null +++ b/huia-compiler/src/scope.rs @@ -0,0 +1,32 @@ +use crate::identifier::Identifier; +use crate::object::Object; +use std::sync::RwLock; + +// Uses a vec of ident-object pairs to ensure that assignments are in SSA form. + +#[derive(Debug, Default)] +pub struct Scope(RwLock>); + +impl Scope { + pub fn new() -> Scope { + Scope(RwLock::new(Vec::new())) + } + + pub fn is_empty(&self) -> bool { + let scope = self.0.read().unwrap(); + scope.is_empty() + } + + pub fn set(&self, name: Identifier, value: Object) { + let mut scope = self.0.write().unwrap(); + scope.push((name, value)) + } + + pub fn get(&self, name: Identifier) -> Option { + let scope = self.0.write().unwrap(); + match scope.iter().rev().find(|(n, _)| n == &name) { + Some((_, o)) => Some(o.clone()), + None => None, + } + } +} diff --git a/huia-compiler/src/stack.rs b/huia-compiler/src/stack.rs new file mode 100644 index 0000000..f264704 --- /dev/null +++ b/huia-compiler/src/stack.rs @@ -0,0 +1,23 @@ +use std::fmt::Debug; + +#[derive(Debug, Default)] +pub struct Stack(Vec); + +impl Stack { + pub fn new() -> Stack { + Stack(Vec::new()) + } + + pub fn push(&mut self) { + self.0.push(T::default()) + } + + pub fn pop(&mut self) -> Option { + self.0.pop() + } + + pub fn current(&self) -> &T { + let idx = self.0.len() - 1; + self.0.get(idx).unwrap() + } +} diff --git a/huia-compiler/src/trait/actual.rs b/huia-compiler/src/trait/actual.rs deleted file mode 100644 index fdaead8..0000000 --- a/huia-compiler/src/trait/actual.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::identifier::Identifier; -use crate::r#trait::TraitId; -use crate::r#type::Type; -use crate::type_spec::TypeSpec; -use std::sync::RwLock; -use wrc::WRC; - -#[derive(Debug, Clone)] -pub struct Trait(WRC>); - -#[derive(Debug)] -pub struct TraitInner { - id: TraitId, - name: Identifier, - requires: TypeSpec, -} - -impl TraitInner { - fn id(&self) -> TraitId { - self.id - } - - fn name(&self) -> Identifier { - self.name - } - - fn set_name(&mut self, name: Identifier) { - self.name = name - } -} - -impl Trait { - pub fn new(id: TraitId, name: Identifier) -> Trait { - let requires = TypeSpec::new(); - Trait(WRC::new(RwLock::new(TraitInner { id, name, requires }))) - } - - pub fn id(&self) -> TraitId { - let tr = self.0.read().unwrap(); - tr.id() - } - - pub fn name(&self) -> Identifier { - let tr = self.0.read().unwrap(); - tr.name() - } - - pub fn set_name(&self, name: Identifier) { - let mut tr = self.0.write().unwrap(); - tr.set_name(name); - } - - pub fn require>(&self, r#type: T) { - let ty: Type = r#type.into(); - let mut tr = self.0.write().unwrap(); - tr.requires.push(ty); - } - - pub fn requires>(&self, r#type: T) -> bool { - let ty: Type = r#type.into(); - let tr = self.0.read().unwrap(); - tr.requires.matches(ty) - } -} - -impl PartialEq for Trait { - fn eq(&self, other: &Trait) -> bool { - self.id() == other.id() - } -} - -#[cfg(test)] -mod test { - use crate::context::Context; - - #[test] - fn set_name() { - let mut context = Context::new(); - let tr = context.new_trait("Marty McFly"); - assert_eq!(tr.name(), context.identifiers().get("Marty McFly")); - tr.set_name(context.identifiers().get("Doc Brown")); - assert_eq!(tr.name(), context.identifiers().get("Doc Brown")); - } - - #[test] - fn requires() { - let mut context = Context::new(); - let tr0 = context.new_trait("Marty McFly"); - - let tr1 = context.new_trait("Doc Brown"); - let cl0 = context.new_class("Einstein Brown"); - - tr0.require(tr1.id()); - tr0.require(cl0.id()); - - assert!(tr0.requires(tr1)); - assert!(tr0.requires(cl0)); - } -} diff --git a/huia-compiler/src/trait/mod.rs b/huia-compiler/src/trait/mod.rs deleted file mode 100644 index 3f26abf..0000000 --- a/huia-compiler/src/trait/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod actual; -mod trait_id; -mod traits; -pub use actual::Trait; -pub use trait_id::TraitId; -pub use traits::Traits; diff --git a/huia-compiler/src/trait/trait_id.rs b/huia-compiler/src/trait/trait_id.rs deleted file mode 100644 index d9fc83c..0000000 --- a/huia-compiler/src/trait/trait_id.rs +++ /dev/null @@ -1,14 +0,0 @@ -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct TraitId(usize); - -impl From for usize { - fn from(data: TraitId) -> usize { - data.0 - } -} - -impl From for TraitId { - fn from(data: usize) -> TraitId { - TraitId(data) - } -} diff --git a/huia-compiler/src/trait/traits.rs b/huia-compiler/src/trait/traits.rs deleted file mode 100644 index 19caf71..0000000 --- a/huia-compiler/src/trait/traits.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::identifier::Identifier; -use crate::r#trait::{Trait, TraitId}; -use std::sync::RwLock; - -#[derive(Default, Debug)] -pub struct Traits(RwLock>); - -impl Traits { - pub fn new() -> Traits { - Traits(RwLock::new(Vec::new())) - } - - pub fn push(&mut self, r#trait: Trait) -> TraitId { - let mut elements = self.0.write().unwrap(); - let idx = elements.len(); - elements.push(r#trait); - TraitId::from(idx) - } - - pub fn get(&self, idx: TraitId) -> Option { - let elements = self.0.read().unwrap(); - match elements.get(usize::from(idx)) { - Some(tr) => Some(tr.clone()), - None => None, - } - } - - pub fn next_id(&self) -> TraitId { - let elements = self.0.read().unwrap(); - TraitId::from(elements.len()) - } - - pub fn find(&self, name: Identifier) -> Option { - let elements = self.0.read().unwrap(); - let tr = elements.iter().find(|tr| tr.name() == name); - match tr { - Some(tr) => Some(tr.id()), - None => None, - } - } - - pub fn is_empty(&self) -> bool { - let elements = self.0.read().unwrap(); - elements.is_empty() - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::identifier::Identifiers; - - #[test] - fn test() { - let identifiers = Identifiers::new(); - let mut traits = Traits::new(); - - let id = traits.next_id(); - let name = identifiers.get("Marty McFly"); - let trait0 = Trait::new(id, name); - - let idx = traits.push(trait0); - assert_eq!(usize::from(idx), 0); - - let trait1 = traits.get(idx).unwrap(); - assert_eq!(trait1.id(), id); - assert_eq!(trait1.name(), identifiers.get("Marty McFly")); - } - -} diff --git a/huia-compiler/src/traits/actual.rs b/huia-compiler/src/traits/actual.rs new file mode 100644 index 0000000..301f2b2 --- /dev/null +++ b/huia-compiler/src/traits/actual.rs @@ -0,0 +1,123 @@ +use crate::identifier::Identifier; +use crate::method::{Method, MethodId}; +use crate::type_spec::TypeSpec; +use crate::types::TypeId; +use crate::vtable::VTable; +use std::sync::RwLock; +use wrc::WRC; + +#[derive(Debug, Clone)] +pub struct Trait(WRC>); + +#[derive(Debug)] +pub struct TraitInner { + id: TypeId, + name: Identifier, + requires: TypeSpec, + vtable: VTable, +} + +impl TraitInner { + fn id(&self) -> TypeId { + self.id + } + + fn name(&self) -> Identifier { + self.name + } + + fn set_name(&mut self, name: Identifier) { + self.name = name + } + + fn add_method(&mut self, method: Method) -> MethodId { + self.vtable.add_method(method) + } + + fn next_id(&self) -> MethodId { + self.vtable.next_id() + } +} + +impl Trait { + pub fn new(id: TypeId, name: Identifier) -> Trait { + let requires = TypeSpec::new(); + let vtable = VTable::new(); + Trait(WRC::new(RwLock::new(TraitInner { + id, + name, + requires, + vtable, + }))) + } + + pub fn id(&self) -> TypeId { + let tr = self.0.read().unwrap(); + tr.id() + } + + pub fn name(&self) -> Identifier { + let tr = self.0.read().unwrap(); + tr.name() + } + + pub fn set_name(&self, name: Identifier) { + let mut tr = self.0.write().unwrap(); + tr.set_name(name); + } + + pub fn require(&self, ty: TypeId) { + let mut tr = self.0.write().unwrap(); + tr.requires.push(ty); + } + + pub fn requires>(&self, ty: T) -> bool { + let tr = self.0.read().unwrap(); + tr.requires.matches(ty.into()) + } + + pub fn add_method(&self, method: Method) -> MethodId { + let mut tr = self.0.write().unwrap(); + tr.add_method(method) + } + + pub fn next_id(&self) -> MethodId { + let tr = self.0.read().unwrap(); + tr.next_id() + } +} + +impl PartialEq for Trait { + fn eq(&self, other: &Trait) -> bool { + self.id() == other.id() + } +} + +#[cfg(test)] +mod test { + use crate::context::Context; + + #[test] + fn set_name() { + let mut context = Context::new(); + let tr = context.ensure_trait(context.ident("Marty McFly")); + assert_eq!(tr.name(), context.ident("Marty McFly")); + tr.set_name(context.ident("Doc Brown")); + assert_eq!(tr.name(), context.ident("Doc Brown")); + } + + #[test] + fn requires() { + let mut context = Context::new(); + let tr0 = context.ensure_trait(context.ident("Marty McFly")); + + let tr1 = context.ensure_trait(context.ident("Doc Brown")); + let cl0 = context.ensure_class(context.ident("Einstein Brown")); + + tr0.require(tr1.id()); + tr0.require(cl0.id()); + + assert!(tr0.requires(tr1)); + assert!(tr0.requires(cl0)); + } +} diff --git a/huia-compiler/src/traits/mod.rs b/huia-compiler/src/traits/mod.rs new file mode 100644 index 0000000..b7f6b71 --- /dev/null +++ b/huia-compiler/src/traits/mod.rs @@ -0,0 +1,2 @@ +mod actual; +pub use actual::Trait; diff --git a/huia-compiler/src/type.rs b/huia-compiler/src/type.rs deleted file mode 100644 index 57a95c6..0000000 --- a/huia-compiler/src/type.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::class::{Class, ClassId}; -use crate::r#trait::{Trait, TraitId}; - -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub enum Type { - Class(ClassId), - Trait(TraitId), -} - -impl Type { - pub fn is_class(&self) -> bool { - match self { - Type::Class(_) => true, - _ => false, - } - } - - pub fn is_trait(&self) -> bool { - match self { - Type::Trait(_) => true, - _ => false, - } - } - - pub fn class_id(&self) -> Option { - match self { - Type::Class(id) => Some(*id), - _ => None, - } - } - - pub fn trait_id(&self) -> Option { - match self { - Type::Trait(id) => Some(*id), - _ => None, - } - } -} - -impl From for Type { - fn from(id: ClassId) -> Type { - Type::Class(id) - } -} - -impl From for Type { - fn from(id: TraitId) -> Type { - Type::Trait(id) - } -} - -impl From for Type { - fn from(class: Class) -> Type { - Type::Class(class.id()) - } -} - -impl From for Type { - fn from(tr: Trait) -> Type { - Type::Trait(tr.id()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test() { - let ty0 = Type::from(ClassId::from(0)); - let ty1 = Type::from(TraitId::from(0)); - - assert_ne!(ty0, ty1); - assert!(ty0.is_class()); - assert!(ty1.is_trait()); - - assert_eq!(ty0.class_id().unwrap(), ClassId::from(0)); - assert_eq!(ty1.trait_id().unwrap(), TraitId::from(0)); - } -} diff --git a/huia-compiler/src/type_spec.rs b/huia-compiler/src/type_spec.rs index 9a63347..db7df09 100644 --- a/huia-compiler/src/type_spec.rs +++ b/huia-compiler/src/type_spec.rs @@ -1,45 +1,27 @@ -use crate::r#type::Type; +use crate::types::TypeId; #[derive(Debug, Default)] -pub struct TypeSpec(Vec); +pub struct TypeSpec(Vec); impl TypeSpec { pub fn new() -> TypeSpec { TypeSpec(Vec::new()) } - pub fn push(&mut self, ty: Type) { + pub fn push(&mut self, ty: TypeId) { self.0.push(ty) } - pub fn matches(&self, ty: Type) -> bool { + pub fn matches(&self, ty: TypeId) -> bool { self.0.iter().any(|i| i == &ty) } } -impl> From for TypeSpec { +impl> From for TypeSpec { fn from(ty: T) -> TypeSpec { - let ty: Type = ty.into(); + let ty: TypeId = ty.into(); let mut ts = TypeSpec::new(); ts.push(ty); ts } } - -#[cfg(test)] -mod test { - use super::*; - use crate::class::ClassId; - use crate::r#trait::TraitId; - - #[test] - fn test() { - let mut type_spec = TypeSpec::new(); - let ty0 = Type::from(ClassId::from(0)); - let ty1 = Type::from(TraitId::from(0)); - assert!(ty0.is_class()); - assert!(ty1.is_trait()); - type_spec.push(ty0); - type_spec.push(ty1); - } -} diff --git a/huia-compiler/src/types/actual.rs b/huia-compiler/src/types/actual.rs new file mode 100644 index 0000000..ae4d1d5 --- /dev/null +++ b/huia-compiler/src/types/actual.rs @@ -0,0 +1,112 @@ +use crate::classes::Class; +use crate::identifier::Identifier; +use crate::traits::Trait; +use crate::types::TypeId; + +#[derive(Debug, Clone)] +pub enum Type { + Class(Class), + Trait(Trait), +} + +impl Type { + pub fn new>(inner: T) -> Type { + inner.into() + } + + pub fn id(&self) -> TypeId { + match self { + Type::Class(t) => t.id(), + Type::Trait(t) => t.id(), + } + } + + pub fn name(&self) -> Identifier { + match self { + Type::Class(t) => t.name(), + Type::Trait(t) => t.name(), + } + } + + pub fn as_class(&self) -> Option { + match self { + Type::Class(t) => Some(t.clone()), + _ => None, + } + } + + pub fn as_trait(&self) -> Option { + match self { + Type::Trait(t) => Some(t.clone()), + _ => None, + } + } + + pub fn is_class(&self) -> bool { + match self { + Type::Class(_) => true, + _ => false, + } + } + + pub fn is_trait(&self) -> bool { + match self { + Type::Trait(_) => true, + _ => false, + } + } +} + +impl From for Type { + fn from(class: Class) -> Type { + Type::Class(class) + } +} + +impl From for Type { + fn from(tr: Trait) -> Type { + Type::Trait(tr) + } +} + +impl PartialEq for Type { + fn eq(&self, other: &Type) -> bool { + self.id() == other.id() + } +} + +impl PartialEq for Type { + fn eq(&self, other: &Class) -> bool { + match self { + Type::Class(c) => c.id() == other.id(), + _ => false, + } + } +} + +impl PartialEq for Type { + fn eq(&self, other: &Trait) -> bool { + match self { + Type::Trait(c) => c.id() == other.id(), + _ => false, + } + } +} + +impl PartialEq for Trait { + fn eq(&self, other: &Type) -> bool { + match other { + Type::Trait(c) => c.id() == self.id(), + _ => false, + } + } +} + +impl PartialEq for Class { + fn eq(&self, other: &Type) -> bool { + match other { + Type::Class(c) => c.id() == self.id(), + _ => false, + } + } +} diff --git a/huia-compiler/src/types/mod.rs b/huia-compiler/src/types/mod.rs new file mode 100644 index 0000000..33c99a5 --- /dev/null +++ b/huia-compiler/src/types/mod.rs @@ -0,0 +1,6 @@ +mod actual; +mod type_id; +mod table; +pub use actual::Type; +pub use type_id::TypeId; +pub use table::TypeTable; diff --git a/huia-compiler/src/types/table.rs b/huia-compiler/src/types/table.rs new file mode 100644 index 0000000..e3df96c --- /dev/null +++ b/huia-compiler/src/types/table.rs @@ -0,0 +1,45 @@ +use crate::identifier::Identifier; +use crate::types::{Type, TypeId}; +use std::sync::RwLock; + +#[derive(Default, Debug)] +pub struct TypeTable(RwLock>); + +impl TypeTable { + pub fn new() -> TypeTable { + TypeTable(RwLock::new(Vec::new())) + } + + pub fn push>(&self, ty: T) -> TypeId { + let mut elements = self.0.write().unwrap(); + let ty: Type = ty.into(); + elements.push(ty.clone()); + ty.id() + } + + pub fn get(&self, idx: TypeId) -> Option { + let elements = self.0.read().unwrap(); + match elements.get(usize::from(idx)) { + Some(ty) => Some(ty.clone()), + None => None, + } + } + + pub fn next_id(&self) -> TypeId { + let elements = self.0.read().unwrap(); + TypeId::from(elements.len()) + } + + pub fn find(&self, name: Identifier) -> Option { + let elements = self.0.read().unwrap(); + match elements.iter().find(|ty| ty.name() == name) { + Some(ty) => Some(ty.clone()), + None => None, + } + } + + pub fn is_empty(&self) -> bool { + let elements = self.0.read().unwrap(); + elements.is_empty() + } +} diff --git a/huia-compiler/src/types/type_id.rs b/huia-compiler/src/types/type_id.rs new file mode 100644 index 0000000..3f8efed --- /dev/null +++ b/huia-compiler/src/types/type_id.rs @@ -0,0 +1,29 @@ +use crate::classes::Class; +use crate::traits::Trait; + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct TypeId(usize); + +impl From for TypeId { + fn from(cl: Class) -> TypeId { + cl.id() + } +} + +impl From for TypeId { + fn from(tr: Trait) -> TypeId { + tr.id() + } +} + +impl From for usize { + fn from(id: TypeId) -> usize { + id.0 + } +} + +impl From for TypeId { + fn from(id: usize) -> TypeId { + TypeId(id) + } +} diff --git a/huia-compiler/src/vtable.rs b/huia-compiler/src/vtable.rs new file mode 100644 index 0000000..1307c87 --- /dev/null +++ b/huia-compiler/src/vtable.rs @@ -0,0 +1,31 @@ +use crate::method::{Method, MethodId}; + +#[derive(Debug, Default)] +pub struct VTable(Vec); + +impl VTable { + pub fn new() -> VTable { + VTable(Vec::new()) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn add_method(&mut self, method: Method) -> MethodId { + let idx = self.0.len(); + self.0.push(method); + MethodId::from(idx) + } + + pub fn get(&self, idx: MethodId) -> Option { + match self.0.get(usize::from(idx)) { + Some(method) => Some(method.clone()), + None => None, + } + } + + pub fn next_id(&self) -> MethodId { + MethodId::from(self.0.len()) + } +} diff --git a/huia-parser/src/ast/float.rs b/huia-parser/src/ast/float.rs index 14b5ee1..8a5e34e 100644 --- a/huia-parser/src/ast/float.rs +++ b/huia-parser/src/ast/float.rs @@ -55,6 +55,6 @@ mod test { .next() .unwrap(); let float = Float::from(pair); - assert_eq!(float.value(), 123.456); + assert!(float.value() - 123.456 < std::f64::EPSILON); } } diff --git a/huia-parser/src/ast/mod.rs b/huia-parser/src/ast/mod.rs index 3657201..09a8736 100644 --- a/huia-parser/src/ast/mod.rs +++ b/huia-parser/src/ast/mod.rs @@ -1,25 +1,25 @@ mod atom; mod binary; mod boolean; -mod constant; mod float; mod identifier; mod integer; mod local; mod string; mod term; +mod typename; mod unary; pub use atom::Atom; pub use binary::Binary; pub use boolean::Boolean; -pub use constant::Constant; pub use float::Float; pub use identifier::Identifier; pub use integer::Integer; pub use local::Local; pub use string::String; pub use term::{NodeType, Term}; +pub use typename::Type; pub use unary::Unary; use crate::input_location::InputLocation; diff --git a/huia-parser/src/ast/term.rs b/huia-parser/src/ast/term.rs index 54c07d7..cd9aadd 100644 --- a/huia-parser/src/ast/term.rs +++ b/huia-parser/src/ast/term.rs @@ -23,7 +23,7 @@ pub enum NodeType { Binary, Boolean, Call, - Constant, + Type, Constructor, Declaration, Definition, @@ -43,8 +43,8 @@ enum Inner { Binary(Binary, Box, Box), Boolean(Boolean), Call(Identifier, Vec), - Constant(Constant), - Constructor(Constant, Vec<(Identifier, Term)>), + Type(Type), + Constructor(Type, Vec<(Identifier, Term)>), Declaration(Identifier, Box), Definition( Identifier, @@ -68,9 +68,8 @@ impl Term { match result { Ok(pairs) => { let terms: Vec = pairs - .into_iter() .take_while(|pair| pair.as_rule() != Rule::EOI) - .map(|pair| Term::from(pair)) + .map(Term::from) .collect(); Ok(terms) } @@ -92,7 +91,7 @@ impl Term { Inner::Boolean(_) => NodeType::Boolean, Inner::Binary(_, _, _) => NodeType::Binary, Inner::Call(_, _) => NodeType::Call, - Inner::Constant(_) => NodeType::Constant, + Inner::Type(_) => NodeType::Type, Inner::Constructor(_, _) => NodeType::Constructor, Inner::Definition(_, _, _, _, _) => NodeType::Definition, Inner::Declaration(_, _) => NodeType::Declaration, @@ -141,16 +140,16 @@ impl Term { } } - pub fn constant(&self) -> Option<&Constant> { + pub fn typename(&self) -> Option<&Type> { match self.inner { - Inner::Constant(ref node) => Some(node), + Inner::Type(ref node) => Some(node), _ => None, } } - pub fn constructor(&self) -> Option<(&Constant, &Vec<(Identifier, Term)>)> { + pub fn constructor(&self) -> Option<(&Type, &Vec<(Identifier, Term)>)> { match self.inner { - Inner::Constructor(ref constant, ref properties) => Some((constant, properties)), + Inner::Constructor(ref typename, ref properties) => Some((typename, properties)), _ => None, } } @@ -243,7 +242,7 @@ impl<'a> From> for Term { Rule::array => { let mut result = Vec::new(); - for element in pair.clone().into_inner().into_iter() { + for element in pair.clone().into_inner() { result.push(Term::from(element)); } @@ -264,7 +263,7 @@ impl<'a> From> for Term { let mut inner = pair.clone().into_inner(); let name = Identifier::from(inner.next().unwrap()); let mut args = Vec::new(); - for argument in inner.into_iter() { + for argument in inner { match argument.as_rule() { Rule::call_argument => { args.push(Term::from(argument.into_inner().next().unwrap())) @@ -277,16 +276,16 @@ impl<'a> From> for Term { inner: Inner::Call(name, args), } } - Rule::constant => Term { + Rule::typename => Term { location: InputLocation::from(pair.clone()), - inner: Inner::Constant(Constant::from(pair)), + inner: Inner::Type(Type::from(pair)), }, Rule::constructor => { let mut inner = pair.clone().into_inner(); - let constant = Constant::from(inner.next().unwrap()); + let typename = Type::from(inner.next().unwrap()); let mut properties = Vec::new(); - for property in inner.into_iter() { + for property in inner { match property.as_rule() { Rule::constructor_property => { let mut proppairs = property.into_inner(); @@ -300,7 +299,7 @@ impl<'a> From> for Term { Term { location: InputLocation::from(pair), - inner: Inner::Constructor(constant, properties), + inner: Inner::Constructor(typename, properties), } } Rule::declaration => { @@ -329,49 +328,43 @@ impl<'a> From> for Term { let mut typeargs = Vec::new(); - match typeargspair.next() { - Some(arguments) => { - for argument in arguments.into_inner().into_iter() { - let mut argument = argument.into_inner(); - let argname = Identifier::from(argument.next().unwrap()); - let argvalue = Term::from(argument.next().unwrap()); - typeargs.push((argname, argvalue)); - } + if let Some(arguments) = typeargspair.next() { + for argument in arguments.into_inner() { + let mut argument = argument.into_inner(); + let argname = Identifier::from(argument.next().unwrap()); + let argvalue = Term::from(argument.next().unwrap()); + typeargs.push((argname, argvalue)); } - None => (), } let mut requirements = Vec::new(); - match typeargspair.next() { - Some(requirement) => match requirement.as_rule() { + if let Some(requirement) = typeargspair.next() { + match requirement.as_rule() { Rule::definition_requirement => { - for constant in requirement.clone().into_inner().into_iter() { - let constant = Term::from(constant); - requirements.push(constant); + for typename in requirement.clone().into_inner() { + let typename = Term::from(typename); + requirements.push(typename); } } _ => unreachable!("Expected pair to be a Requirement"), - }, - None => (), - }; + } + } let mut bodyargs = Vec::new(); - match inner.next() { - Some(arguments) => { - for argument in arguments.into_inner().into_iter() { - let mut arg_inner = argument.into_inner(); - let argname = Identifier::from(arg_inner.next().unwrap()); - let mut body: Vec = vec![]; - for argvalue in arg_inner.into_iter() { - body.push(Term::from(argvalue)); - } - bodyargs.push((argname, body)); + if let Some(arguments) = inner.next() { + for argument in arguments.into_inner() { + let mut arg_inner = argument.into_inner(); + let argname = Identifier::from(arg_inner.next().unwrap()); + let mut body: Vec = vec![]; + for argvalue in arg_inner { + body.push(Term::from(argvalue)); } + bodyargs.push((argname, body)); } - None => (), } + Term { location: InputLocation::from(pair), inner: Inner::Definition( @@ -399,7 +392,7 @@ impl<'a> From> for Term { Rule::map => { let mut contents = Vec::new(); - for map_pair in pair.clone().into_inner().into_iter() { + for map_pair in pair.clone().into_inner() { let mut inner = map_pair.into_inner(); let keypair = inner.next().unwrap(); let key = match keypair.as_rule() { @@ -424,7 +417,7 @@ impl<'a> From> for Term { let mut call = inner.next().unwrap().into_inner(); let name = Identifier::from(call.next().unwrap()); let mut args = Vec::new(); - for argument in call.into_iter() { + for argument in call { match argument.as_rule() { Rule::call_argument => { args.push(Term::from(argument.into_inner().next().unwrap())) @@ -541,8 +534,8 @@ mod test { #[test] fn test_constant() { let terms = Term::input("Marty").unwrap(); - assert_eq!(terms[0].node_type(), NodeType::Constant); - let term = terms[0].constant().unwrap().clone(); + assert_eq!(terms[0].node_type(), NodeType::Type); + let term = terms[0].typename().unwrap().clone(); assert_eq!(term.value(), "Marty"); } @@ -550,16 +543,16 @@ mod test { fn test_constructor_empty() { let terms = Term::input("Character {}").unwrap(); assert_eq!(terms[0].node_type(), NodeType::Constructor); - let (constant, properties) = terms[0].constructor().unwrap(); - assert_eq!(constant.value_ref(), "Character"); + let (typename, properties) = terms[0].constructor().unwrap(); + assert_eq!(typename.value_ref(), "Character"); assert_eq!(properties.len(), 0); } #[test] fn test_constructor() { let terms = Term::input("Character { name: \"Marty McFly\" }").unwrap(); - let (constant, properties) = terms[0].constructor().unwrap(); - assert_eq!(constant.value_ref(), "Character"); + let (typename, properties) = terms[0].constructor().unwrap(); + assert_eq!(typename.value_ref(), "Character"); assert_eq!(properties.len(), 1); let (key, value) = &properties[0]; assert_eq!(key.value_ref(), "name"); @@ -571,13 +564,13 @@ mod test { let terms = Term::input("type Delorean(speed: Integer) do\n123\n\n456\nend").unwrap(); assert_eq!(terms[0].node_type(), NodeType::Definition); - let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "type"); - assert_eq!(defname.constant().unwrap().value_ref(), "Delorean"); + assert_eq!(defname.typename().unwrap().value_ref(), "Delorean"); let (argname, argvalue) = &args[0]; assert_eq!(argname.value_ref(), "speed"); - assert_eq!(argvalue.constant().unwrap().value_ref(), "Integer"); + assert_eq!(argvalue.typename().unwrap().value_ref(), "Integer"); let (argname, argvalues) = &body[0]; assert_eq!(argname.value_ref(), "do"); @@ -589,9 +582,9 @@ mod test { #[test] fn test_definition_empty() { let terms = Term::input("type Delorean").unwrap(); - let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "type"); - assert_eq!(defname.constant().unwrap().value_ref(), "Delorean"); + assert_eq!(defname.typename().unwrap().value_ref(), "Delorean"); assert_eq!(args.len(), 0); assert_eq!(body.len(), 0); } @@ -599,7 +592,7 @@ mod test { #[test] fn test_definition_empty_fun() { let terms = Term::input("def hello()").unwrap(); - let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "def"); assert_eq!(defname.atom().unwrap().value_ref(), "hello"); assert_eq!(args.len(), 0); @@ -609,7 +602,7 @@ mod test { #[test] fn test_definition_fun() { let terms = Term::input("def example(a: Integer, b: Atom), do: 123").unwrap(); - let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, _reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "def"); assert_eq!(defname.atom().unwrap().value_ref(), "example"); assert_eq!(args.len(), 2); @@ -619,27 +612,27 @@ mod test { #[test] fn test_definition_fun_w_return_type() { let terms = Term::input("def example(a: Integer, b: Atom): Integer, do: 123").unwrap(); - let (deftype, defname, args, body, reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "def"); assert_eq!(defname.atom().unwrap().value_ref(), "example"); assert_eq!(args.len(), 2); assert_eq!(body.len(), 1); - assert_eq!(reqs[0].constant().unwrap().value_ref(), "Integer"); + assert_eq!(reqs[0].typename().unwrap().value_ref(), "Integer"); } #[test] fn test_definition_trait_with_bounds() { let terms = Term::input("trait Integer: Add + Subtract + Divide + Multiply").unwrap(); - let (deftype, defname, args, body, reqs) = terms[0].definition().unwrap().clone(); + let (deftype, defname, args, body, reqs) = terms[0].definition().unwrap(); assert_eq!(deftype.value_ref(), "trait"); - assert_eq!(defname.constant().unwrap().value_ref(), "Integer"); + assert_eq!(defname.typename().unwrap().value_ref(), "Integer"); assert_eq!(args.len(), 0); assert_eq!(body.len(), 0); assert_eq!(reqs.len(), 4); - assert_eq!(reqs[0].constant().unwrap().value_ref(), "Add"); - assert_eq!(reqs[1].constant().unwrap().value_ref(), "Subtract"); - assert_eq!(reqs[2].constant().unwrap().value_ref(), "Divide"); - assert_eq!(reqs[3].constant().unwrap().value_ref(), "Multiply"); + assert_eq!(reqs[0].typename().unwrap().value_ref(), "Add"); + assert_eq!(reqs[1].typename().unwrap().value_ref(), "Subtract"); + assert_eq!(reqs[2].typename().unwrap().value_ref(), "Divide"); + assert_eq!(reqs[3].typename().unwrap().value_ref(), "Multiply"); } #[test] @@ -658,7 +651,7 @@ mod test { let terms = Term::input("1.23").unwrap(); assert_eq!(terms[0].node_type(), NodeType::Float); let node = terms[0].float().unwrap(); - assert_eq!(node.value_ref(), &1.23); + assert!(node.value_ref() - 1.23 < std::f64::EPSILON); } #[test] @@ -760,7 +753,7 @@ mod test { let terms = Term::input("My.Greeter.hello()").unwrap(); let (method_name, receiver, arguments) = terms[0].method_call().unwrap(); assert_eq!(method_name.value_ref(), "hello"); - assert_eq!(receiver.constant().unwrap().value_ref(), "My.Greeter"); + assert_eq!(receiver.typename().unwrap().value_ref(), "My.Greeter"); assert_eq!(arguments.len(), 0); } diff --git a/huia-parser/src/ast/constant.rs b/huia-parser/src/ast/typename.rs similarity index 70% rename from huia-parser/src/ast/constant.rs rename to huia-parser/src/ast/typename.rs index f8c2415..7af5aee 100644 --- a/huia-parser/src/ast/constant.rs +++ b/huia-parser/src/ast/typename.rs @@ -4,18 +4,18 @@ use crate::input_location::InputLocation; use pest::iterators::Pair; #[derive(Debug, Clone)] -pub struct Constant { +pub struct Type { value: String, location: InputLocation, } -impl Constant { +impl Type { pub fn value(&self) -> &str { &self.value } } -impl Value for Constant { +impl Value for Type { type Item = String; fn value(self) -> Self::Item { @@ -27,23 +27,23 @@ impl Value for Constant { } } -impl Location for Constant { +impl Location for Type { fn location(&self) -> &InputLocation { &self.location } } -impl<'a> From> for Constant { +impl<'a> From> for Type { fn from(pair: Pair<'a, Rule>) -> Self { match pair.as_rule() { - Rule::constant => { + Rule::typename => { let value = pair.clone().into_span().as_str().to_string(); - Constant { + Type { value: value, location: InputLocation::from(pair.into_span()), } } - _ => unreachable!("Expected pair to be an Constant"), + _ => unreachable!("Expected pair to be an Type"), } } } @@ -56,11 +56,11 @@ mod test { #[test] fn it_parses() { - let pair = Grammar::parse(Rule::constant, "Marty.McFly") + let pair = Grammar::parse(Rule::typename, "Marty.McFly") .unwrap() .next() .unwrap(); - let constant = Constant::from(pair); - assert_eq!(constant.value(), "Marty.McFly"); + let r#type = Type::from(pair); + assert_eq!(r#type.value(), "Marty.McFly"); } } diff --git a/huia-parser/src/grammar.pest b/huia-parser/src/grammar.pest index 4ae1558..871e148 100644 --- a/huia-parser/src/grammar.pest +++ b/huia-parser/src/grammar.pest @@ -20,23 +20,23 @@ call_arguments = _{ "(" ~ (call_argument ~ ("," ~ call_argument)* )? ~ ")" } call_argument = { expression } definition = { ident ~ definition_what ~ arguments } -definition_what = { (ident | constant) ~ definition_arguments ~ definition_requirement_opt } +definition_what = { (ident | typename) ~ definition_arguments ~ definition_requirement_opt } definition_arguments = { ("(" ~ (definition_argument ~ ("," ~ definition_argument)* )? ~ ")")? } definition_requirement_opt = _{ (":" ~ definition_requirement)? } -definition_requirement = { constant ~ ("+" ~ constant)* } -definition_argument = { keyword ~ constant } +definition_requirement = { typename ~ ("+" ~ typename)* } +definition_argument = { keyword ~ typename } arguments = { argument* } argument = { argument_block | argument_short } argument_block = _{ ident ~ expression* ~ "end" } argument_short = _{ "," ~ keyword ~ expression } -literal = _{ constructor | map | array | constant | string | atom | float | integer | boolean } +literal = _{ constructor | map | array | typename | string | atom | float | integer | boolean } ident = @{ !reserved ~ 'a'..'z' ~ ('a'..'z' | 'A'..'Z' | "_")* } keyword = @{ ident ~ ":" } -constructor = { constant ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" } +constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" } constructor_property = { keyword ~ expression } map = { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" } @@ -46,8 +46,8 @@ array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" } atom = @{ ":" ~ ident } -constant = @{ constant_name ~ ("." ~ constant_name)* } -constant_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* } +typename = @{ typename_name ~ ("." ~ typename_name)* } +typename_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* } float = ${ float_characteristic ~ "." ~ float_mantissa } float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) } diff --git a/huia-parser/src/precedence.rs b/huia-parser/src/precedence.rs index f62e4d7..8d80e91 100644 --- a/huia-parser/src/precedence.rs +++ b/huia-parser/src/precedence.rs @@ -33,11 +33,11 @@ fn build_precedence_climber() -> PrecClimber { ]) } -fn build_binary<'a>(lhs: Term, op: Pair<'a, Rule>, rhs: Term) -> Term { +fn build_binary(lhs: Term, op: Pair<'_, Rule>, rhs: Term) -> Term { let binary = Binary::from(op); Term::create_infix(binary, lhs, rhs) } -pub fn climb<'a>(pair: Pair<'a, Rule>) -> Term { +pub fn climb(pair: Pair<'_, Rule>) -> Term { PREC_CLIMBER.climb(pair.into_inner(), Term::from, build_binary) }