Beginnings of a much simpler type system.
This commit is contained in:
parent
115c1d51e9
commit
e85fb16707
20 changed files with 465 additions and 734 deletions
|
@ -6,3 +6,5 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
huia-parser = { path = "../huia-parser" }
|
||||
wrc = "0.3.0"
|
||||
string-interner = "0.7.0"
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
use crate::constant::Constant;
|
||||
use crate::context::Context;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn bootstrap(context: &mut Context) {
|
||||
let any_trait = Constant::new_trait("Any", Vec::new());
|
||||
|
||||
context.add_constant(Rc::new(any_trait));
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
use crate::constant::Constant;
|
||||
use crate::context::Context;
|
||||
use crate::method_table::{Method, MethodTable};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn bootstrap(context: &mut Context) {
|
||||
let mut ary_type = Constant::native_array();
|
||||
|
||||
let method = Method::new("new", true);
|
||||
|
||||
ary_type.insert_method(method);
|
||||
ary_type.implement(context.get_constant("Any").unwrap(), MethodTable::new());
|
||||
|
||||
context.add_constant(Rc::new(ary_type));
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
use crate::constant::Constant;
|
||||
use crate::context::Context;
|
||||
|
||||
mod any;
|
||||
mod array;
|
||||
|
||||
pub fn bootstrap(mut context: &mut Context) {
|
||||
any::bootstrap(&mut context);
|
||||
array::bootstrap(&mut context);
|
||||
}
|
|
@ -1,32 +1,134 @@
|
|||
use crate::vtable::{Method, TraitData, VTable, VTableClassData, VTableImplData};
|
||||
use crate::identifier::Identifier;
|
||||
use std::sync::RwLock;
|
||||
use wrc::WRC;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ClassId(usize);
|
||||
|
||||
impl From<ClassId> for usize {
|
||||
fn from(data: ClassId) -> usize {
|
||||
data.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for ClassId {
|
||||
fn from(data: usize) -> ClassId {
|
||||
ClassId(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Classes(RwLock<Vec<Class>>);
|
||||
|
||||
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<Class> {
|
||||
let elements = self.0.read().unwrap();
|
||||
match elements.get(idx.0) {
|
||||
Some(class) => Some(class.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_id(&self) -> ClassId {
|
||||
let elements = self.0.read().unwrap();
|
||||
ClassId(elements.len())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let elements = self.0.read().unwrap();
|
||||
elements.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClassData {
|
||||
name: String,
|
||||
vtable: VTableClassData,
|
||||
impls: Vec<(TraitData, VTableImplData)>,
|
||||
pub struct Class(WRC<RwLock<ClassInner>>);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ClassInner {
|
||||
id: ClassId,
|
||||
name: Identifier,
|
||||
}
|
||||
|
||||
impl ClassData {
|
||||
pub fn new(name: &str) -> ClassData {
|
||||
ClassData {
|
||||
name: name.to_string(),
|
||||
vtable: VTableClassData::new(),
|
||||
impls: Vec::new(),
|
||||
}
|
||||
impl ClassInner {
|
||||
fn id(&self) -> ClassId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
fn name(&self) -> Identifier {
|
||||
self.name
|
||||
}
|
||||
|
||||
fn set_name(&mut self, name: Identifier) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for ClassData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.vtable.insert_method(method)
|
||||
impl Class {
|
||||
pub fn new(id: ClassId, name: Identifier) -> Class {
|
||||
Class(WRC::new(RwLock::new(ClassInner { id, name })))
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.vtable.get_method(id)
|
||||
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 super::*;
|
||||
use crate::context::Context;
|
||||
use crate::identifier::Identifiers;
|
||||
|
||||
#[test]
|
||||
fn classes() {
|
||||
let mut 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!(idx.0, 0);
|
||||
|
||||
let class1 = classes.get(idx).unwrap();
|
||||
assert_eq!(class1.id(), id);
|
||||
assert_eq!(class1.name(), identifiers.get("Marty McFly"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_name() {
|
||||
let mut context = Context::new();
|
||||
let class = context.new_class("Marty McFly");
|
||||
assert_eq!(class.name(), context.get_identifier("Marty McFly"));
|
||||
class.set_name(context.get_identifier("Doc Brown"));
|
||||
assert_eq!(class.name(), context.get_identifier("Doc Brown"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
use crate::method_table::{Method, MethodTable};
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Constant {
|
||||
identifier: String,
|
||||
inner: ConstantInner,
|
||||
methods: MethodTable,
|
||||
implements: Vec<(Rc<Constant>, MethodTable)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConstantInner {
|
||||
NativeBoolean,
|
||||
NativeFloat,
|
||||
NativeInteger,
|
||||
NativeArray,
|
||||
NativeHashMap,
|
||||
UserDefinedType {
|
||||
property_types: BTreeMap<String, Rc<Constant>>,
|
||||
},
|
||||
Trait {
|
||||
corequires: Vec<Rc<Constant>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
type_ref: Rc<Constant>,
|
||||
inner: InstanceInner,
|
||||
}
|
||||
|
||||
pub enum InstanceInner {
|
||||
NativeBoolean(bool),
|
||||
NativeFloat(f64),
|
||||
NativeInteger(i64),
|
||||
}
|
||||
|
||||
impl Constant {
|
||||
pub fn native_array() -> Constant {
|
||||
Constant {
|
||||
identifier: "Huia.NativeArray".to_string(),
|
||||
inner: ConstantInner::NativeArray,
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn native_boolean() -> Constant {
|
||||
Constant {
|
||||
identifier: "Huia.NativeBoolean".to_string(),
|
||||
inner: ConstantInner::NativeBoolean,
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn native_float() -> Constant {
|
||||
Constant {
|
||||
identifier: "Huia.NativeFloat".to_string(),
|
||||
inner: ConstantInner::NativeFloat,
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn native_hash_map() -> Constant {
|
||||
Constant {
|
||||
identifier: "Huia.NativeHashMap".to_string(),
|
||||
inner: ConstantInner::NativeHashMap,
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn native_integer() -> Constant {
|
||||
Constant {
|
||||
identifier: "Huia.NativeInteger".to_string(),
|
||||
inner: ConstantInner::NativeInteger,
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_trait(name: &str, corequires: Vec<Rc<Constant>>) -> Constant {
|
||||
Constant {
|
||||
identifier: name.to_string(),
|
||||
inner: ConstantInner::Trait { corequires },
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_type(name: &str, property_types: BTreeMap<String, Rc<Constant>>) -> Constant {
|
||||
Constant {
|
||||
identifier: name.to_string(),
|
||||
inner: ConstantInner::UserDefinedType { property_types },
|
||||
methods: MethodTable::new(),
|
||||
implements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifier(&self) -> &str {
|
||||
&self.identifier
|
||||
}
|
||||
|
||||
pub fn is_native(&self) -> bool {
|
||||
match self.inner {
|
||||
ConstantInner::NativeArray => true,
|
||||
ConstantInner::NativeBoolean => true,
|
||||
ConstantInner::NativeFloat => true,
|
||||
ConstantInner::NativeHashMap => true,
|
||||
ConstantInner::NativeInteger => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_method(&mut self, method: Method) {
|
||||
self.methods.insert(method);
|
||||
}
|
||||
|
||||
pub fn get_method(&self, name: &str) -> Option<Rc<Method>> {
|
||||
self.methods.get(name)
|
||||
}
|
||||
|
||||
pub fn implement(&mut self, r#trait: Rc<Constant>, method_table: MethodTable) {
|
||||
self.implements.push((r#trait, method_table));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn native_array() {
|
||||
let con = Constant::native_array();
|
||||
assert_eq!(con.identifier(), "Huia.NativeArray");
|
||||
assert!(con.is_native());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_boolean() {
|
||||
let con = Constant::native_boolean();
|
||||
assert_eq!(con.identifier(), "Huia.NativeBoolean");
|
||||
assert!(con.is_native());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_float() {
|
||||
let con = Constant::native_float();
|
||||
assert_eq!(con.identifier(), "Huia.NativeFloat");
|
||||
assert!(con.is_native());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_hash_map() {
|
||||
let con = Constant::native_hash_map();
|
||||
assert_eq!(con.identifier(), "Huia.NativeHashMap");
|
||||
assert!(con.is_native());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_integer() {
|
||||
let con = Constant::native_integer();
|
||||
assert_eq!(con.identifier(), "Huia.NativeInteger");
|
||||
assert!(con.is_native());
|
||||
}
|
||||
}
|
|
@ -1,105 +1,58 @@
|
|||
use crate::bootstrap::bootstrap;
|
||||
use crate::constant::Constant;
|
||||
use crate::scope::Scope;
|
||||
use huia_parser::ast;
|
||||
use huia_parser::ast::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
use crate::class::{Class, ClassId, Classes};
|
||||
use crate::identifier::{Identifier, Identifiers};
|
||||
use crate::r#trait::{Trait, TraitId, Traits};
|
||||
|
||||
pub struct Context {
|
||||
globals: Scope,
|
||||
classes: Classes,
|
||||
traits: Traits,
|
||||
identifiers: Identifiers,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new() -> Context {
|
||||
let globals = Scope::new();
|
||||
let mut context = Context { globals };
|
||||
|
||||
bootstrap(&mut context);
|
||||
|
||||
context
|
||||
}
|
||||
|
||||
pub fn consume(&mut self, terms: Vec<ast::Term>) {
|
||||
for term in terms {
|
||||
match term.node_type() {
|
||||
ast::NodeType::Array => {}
|
||||
ast::NodeType::Atom => {}
|
||||
ast::NodeType::Binary => {}
|
||||
ast::NodeType::Boolean => {}
|
||||
ast::NodeType::Call => {}
|
||||
ast::NodeType::Constant => {}
|
||||
ast::NodeType::Constructor => {}
|
||||
ast::NodeType::Declaration => {}
|
||||
ast::NodeType::Definition => {
|
||||
// let (deftype, defname, args, body) = term.definition().unwrap();
|
||||
// match deftype.value_ref().as_ref() {
|
||||
// "type" => self.define_type(defname, args, body),
|
||||
// "def" => self.define_public_method(defname, args, body),
|
||||
// "defp" => self.define_private_method(defname, args, body),
|
||||
// "defs" => self.define_static_method(defname, args, body),
|
||||
// _ => panic!("Unknown deftype {:?}", deftype),
|
||||
// }
|
||||
}
|
||||
ast::NodeType::Float => {}
|
||||
ast::NodeType::Integer => {}
|
||||
ast::NodeType::Local => {}
|
||||
ast::NodeType::Map => {}
|
||||
ast::NodeType::MethodCall => {}
|
||||
ast::NodeType::String => {}
|
||||
ast::NodeType::Unary => {}
|
||||
Context {
|
||||
classes: Classes::new(),
|
||||
traits: Traits::new(),
|
||||
identifiers: Identifiers::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()
|
||||
}
|
||||
|
||||
fn define_type(
|
||||
&mut self,
|
||||
defname: &ast::Term,
|
||||
args: &Vec<(ast::Identifier, ast::Term)>,
|
||||
body: &Vec<(ast::Identifier, Vec<ast::Term>)>,
|
||||
) {
|
||||
// let name = defname.constant().unwrap().value_ref();
|
||||
// let mut property_types = BTreeMap::new();
|
||||
// for (ident, value) in args {
|
||||
// property_types.insert(ident.value_ref().to_string(), value);
|
||||
// }
|
||||
|
||||
// let t = Constant::new_type(name, property_types);
|
||||
pub fn get_class(&self, id: ClassId) -> Option<Class> {
|
||||
self.classes.get(id)
|
||||
}
|
||||
|
||||
fn define_public_method(
|
||||
&mut self,
|
||||
defname: &ast::Term,
|
||||
args: &Vec<(ast::Identifier, ast::Term)>,
|
||||
body: &Vec<(ast::Identifier, Vec<ast::Term>)>,
|
||||
) {
|
||||
|
||||
pub fn new_trait(&mut self, name: &str) -> Trait {
|
||||
let name = self.identifiers.get(name);
|
||||
let id = self.traits.next_id();
|
||||
let tr = Trait::new(id, name);
|
||||
self.traits.push(tr);
|
||||
self.traits.get(id).unwrap()
|
||||
}
|
||||
|
||||
fn define_private_method(
|
||||
&mut self,
|
||||
defname: &ast::Term,
|
||||
args: &Vec<(ast::Identifier, ast::Term)>,
|
||||
body: &Vec<(ast::Identifier, Vec<ast::Term>)>,
|
||||
) {
|
||||
|
||||
pub fn get_trait(&self, id: TraitId) -> Option<Trait> {
|
||||
self.traits.get(id)
|
||||
}
|
||||
|
||||
fn define_static_method(
|
||||
&mut self,
|
||||
defname: &ast::Term,
|
||||
args: &Vec<(ast::Identifier, ast::Term)>,
|
||||
body: &Vec<(ast::Identifier, Vec<ast::Term>)>,
|
||||
) {
|
||||
|
||||
pub fn get_identifier(&mut self, value: &str) -> Identifier {
|
||||
self.identifiers.get(value)
|
||||
}
|
||||
|
||||
pub fn add_constant(&mut self, constant: Rc<Constant>) {
|
||||
self.globals.insert(constant);
|
||||
pub fn get_identifier_value(&self, identifier: Identifier) -> Option<&str> {
|
||||
self.identifiers.resolve(identifier)
|
||||
}
|
||||
|
||||
pub fn get_constant(&self, name: &str) -> Option<Rc<Constant>> {
|
||||
self.globals.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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,6 +62,16 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn new() {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
let class0 = context.new_class("Marty McFly");
|
||||
let class1 = context.get_class(class0.id()).unwrap();
|
||||
assert_eq!(class0, class1);
|
||||
|
||||
let tr0 = context.new_trait("Doc Brown");
|
||||
let tr1 = context.get_trait(tr0.id()).unwrap();
|
||||
assert_eq!(tr0, tr1);
|
||||
|
||||
let id = context.get_identifier("Einstein Brown");
|
||||
assert_eq!(context.get_identifier_value(id).unwrap(), "Einstein Brown");
|
||||
}
|
||||
}
|
||||
|
|
42
huia-compiler/src/identifier.rs
Normal file
42
huia-compiler/src/identifier.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use string_interner::{StringInterner, Sym};
|
||||
|
||||
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Identifier(Sym);
|
||||
|
||||
pub struct Identifiers(StringInterner<Sym>);
|
||||
|
||||
impl Identifiers {
|
||||
pub fn new() -> Identifiers {
|
||||
Identifiers(StringInterner::default())
|
||||
}
|
||||
|
||||
pub fn get(&mut self, value: &str) -> Identifier {
|
||||
let sym = self.0.get_or_intern(value);
|
||||
Identifier(sym)
|
||||
}
|
||||
|
||||
pub fn resolve(&self, identifier: Identifier) -> Option<&str> {
|
||||
self.0.resolve(identifier.0)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut identifiers = Identifiers::new();
|
||||
|
||||
assert!(identifiers.is_empty());
|
||||
let sym0 = identifiers.get("Marty McFly");
|
||||
let sym1 = identifiers.get("Marty McFly");
|
||||
assert!(!identifiers.is_empty());
|
||||
assert_eq!(sym0, sym1);
|
||||
assert_eq!(identifiers.resolve(sym0).unwrap(), "Marty McFly");
|
||||
}
|
||||
}
|
|
@ -1,10 +1,17 @@
|
|||
extern crate huia_parser;
|
||||
mod bootstrap;
|
||||
mod class;
|
||||
mod constant;
|
||||
mod context;
|
||||
mod method_table;
|
||||
mod scope;
|
||||
mod vtable;
|
||||
extern crate string_interner;
|
||||
extern crate wrc;
|
||||
|
||||
pub use class::ClassData;
|
||||
mod class;
|
||||
mod context;
|
||||
mod identifier;
|
||||
mod r#trait;
|
||||
mod r#type;
|
||||
mod type_spec;
|
||||
|
||||
pub use class::{Class, ClassId};
|
||||
pub use context::Context;
|
||||
pub use identifier::Identifier;
|
||||
pub use r#trait::{Trait, TraitId};
|
||||
pub use r#type::Type;
|
||||
pub use type_spec::TypeSpec;
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
use crate::constant::Constant;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MethodTable(BTreeMap<String, Rc<Method>>);
|
||||
|
||||
impl MethodTable {
|
||||
pub fn new() -> MethodTable {
|
||||
MethodTable(BTreeMap::new())
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, method: Method) {
|
||||
let name = method.identifier();
|
||||
self.0.insert(name.to_string(), Rc::new(method));
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<Rc<Method>> {
|
||||
match self.0.get(name) {
|
||||
Some(m) => Some(m.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Visibility {
|
||||
Public,
|
||||
Private,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Method {
|
||||
identifier: String,
|
||||
visibility: Visibility,
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn new(name: &str, public: bool) -> Method {
|
||||
let visibility = match public {
|
||||
true => Visibility::Public,
|
||||
false => Visibility::Private,
|
||||
};
|
||||
|
||||
Method {
|
||||
identifier: name.to_string(),
|
||||
visibility,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifier(&self) -> &str {
|
||||
&self.identifier
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn method_table() {
|
||||
let mut mt = MethodTable::new();
|
||||
let m = Method::new("marty", true);
|
||||
|
||||
mt.insert(m);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use crate::constant::Constant;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scope(BTreeMap<String, Rc<Constant>>);
|
||||
|
||||
impl Scope {
|
||||
pub fn new() -> Scope {
|
||||
Scope(BTreeMap::new())
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, constant: Rc<Constant>) {
|
||||
self.0.insert(constant.identifier().to_string(), constant);
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<Rc<Constant>> {
|
||||
match self.0.get(name) {
|
||||
Some(c) => Some(c.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
134
huia-compiler/src/trait.rs
Normal file
134
huia-compiler/src/trait.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
use crate::identifier::Identifier;
|
||||
use std::sync::RwLock;
|
||||
use wrc::WRC;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct TraitId(usize);
|
||||
|
||||
impl From<TraitId> for usize {
|
||||
fn from(data: TraitId) -> usize {
|
||||
data.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for TraitId {
|
||||
fn from(data: usize) -> TraitId {
|
||||
TraitId(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Traits(RwLock<Vec<Trait>>);
|
||||
|
||||
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<Trait> {
|
||||
let elements = self.0.read().unwrap();
|
||||
match elements.get(idx.0) {
|
||||
Some(tr) => Some(tr.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_id(&self) -> TraitId {
|
||||
let elements = self.0.read().unwrap();
|
||||
TraitId(elements.len())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let elements = self.0.read().unwrap();
|
||||
elements.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Trait(WRC<RwLock<TraitInner>>);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct TraitInner {
|
||||
id: TraitId,
|
||||
name: Identifier,
|
||||
}
|
||||
|
||||
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 {
|
||||
Trait(WRC::new(RwLock::new(TraitInner { id, name })))
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Trait {
|
||||
fn eq(&self, other: &Trait) -> bool {
|
||||
self.id() == other.id()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::context::Context;
|
||||
use crate::identifier::Identifiers;
|
||||
|
||||
#[test]
|
||||
fn traits() {
|
||||
let mut 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!(idx.0, 0);
|
||||
|
||||
let trait1 = traits.get(idx).unwrap();
|
||||
assert_eq!(trait1.id(), id);
|
||||
assert_eq!(trait1.name(), identifiers.get("Marty McFly"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_name() {
|
||||
let mut context = Context::new();
|
||||
let tr = context.new_trait("Marty McFly");
|
||||
assert_eq!(tr.name(), context.get_identifier("Marty McFly"));
|
||||
tr.set_name(context.get_identifier("Doc Brown"));
|
||||
assert_eq!(tr.name(), context.get_identifier("Doc Brown"));
|
||||
}
|
||||
}
|
68
huia-compiler/src/type.rs
Normal file
68
huia-compiler/src/type.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use crate::class::ClassId;
|
||||
use crate::r#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<ClassId> {
|
||||
match self {
|
||||
Type::Class(id) => Some(id.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_id(&self) -> Option<TraitId> {
|
||||
match self {
|
||||
Type::Trait(id) => Some(id.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClassId> for Type {
|
||||
fn from(id: ClassId) -> Type {
|
||||
Type::Class(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TraitId> for Type {
|
||||
fn from(id: TraitId) -> Type {
|
||||
Type::Trait(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));
|
||||
}
|
||||
}
|
36
huia-compiler/src/type_spec.rs
Normal file
36
huia-compiler/src/type_spec.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use crate::r#type::Type;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeSpec(Vec<Type>);
|
||||
|
||||
impl TypeSpec {
|
||||
pub fn new() -> TypeSpec {
|
||||
TypeSpec(Vec::new())
|
||||
}
|
||||
|
||||
pub fn push(&mut self, ty: Type) {
|
||||
self.0.push(ty)
|
||||
}
|
||||
|
||||
pub fn matches(&self, ty: Type) -> bool {
|
||||
self.0.iter().any(|i| i == &ty)
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
use crate::vtable::{Instance, Requirement};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
return_requirements: Requirement,
|
||||
heads: Vec<FunctionClause>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new() -> Function {
|
||||
Function {
|
||||
return_requirements: Requirement::new(),
|
||||
heads: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionClause {
|
||||
argument_names: Vec<String>,
|
||||
argument_requirements: Vec<Requirement>,
|
||||
function_body: FunctionBody,
|
||||
}
|
||||
|
||||
impl FunctionClause {
|
||||
pub fn new() -> FunctionClause {
|
||||
FunctionClause {
|
||||
argument_names: Vec::new(),
|
||||
argument_requirements: Vec::new(),
|
||||
function_body: FunctionBody::Empty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_argument(&mut self, argument_name: &str, argument_type: Requirement) {
|
||||
self.argument_names.push(argument_name.to_string());
|
||||
self.argument_requirements.push(argument_type);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FunctionBody {
|
||||
Empty,
|
||||
NativeFunction(fn(Instance, Vec<&str>, Vec<Instance>) -> Instance),
|
||||
UserFunction(),
|
||||
}
|
||||
|
||||
impl fmt::Debug for FunctionBody {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
FunctionBody::Empty => write!(f, "Empty"),
|
||||
FunctionBody::NativeFunction(_) => write!(f, "NativeFunction"),
|
||||
FunctionBody::UserFunction() => write!(f, "UserFunction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut f = Function::new();
|
||||
let mut fhead = FunctionClause::new();
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
use crate::vtable::Function;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Method {
|
||||
name: String,
|
||||
flag: MethodFlag,
|
||||
fun: Function,
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn new(name: &str, flag: MethodFlag, fun: Function) -> Method {
|
||||
let name = name.to_string();
|
||||
|
||||
Method { name, flag, fun }
|
||||
}
|
||||
|
||||
pub fn is_public(&self) -> bool {
|
||||
match self.flag {
|
||||
MethodFlag::Public => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_private(&self) -> bool {
|
||||
match self.flag {
|
||||
MethodFlag::Private => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_static(&self) -> bool {
|
||||
match self.flag {
|
||||
MethodFlag::Static => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flag(&self) -> MethodFlag {
|
||||
self.flag.clone()
|
||||
}
|
||||
|
||||
pub fn set_flag(&mut self, flag: MethodFlag) {
|
||||
self.flag = flag;
|
||||
}
|
||||
|
||||
pub fn fun(&self) -> &Function {
|
||||
&self.fun
|
||||
}
|
||||
|
||||
pub fn set_fun(&mut self, fun: Function) {
|
||||
self.fun = fun;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MethodFlag {
|
||||
Public,
|
||||
Private,
|
||||
Static,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let f = Function::new();
|
||||
|
||||
let m = Method::new("marty", MethodFlag::Public, f.clone());
|
||||
assert!(m.is_public());
|
||||
assert!(!m.is_private());
|
||||
assert!(!m.is_static());
|
||||
|
||||
let m = Method::new("marty", MethodFlag::Private, f.clone());
|
||||
assert!(!m.is_public());
|
||||
assert!(m.is_private());
|
||||
assert!(!m.is_static());
|
||||
|
||||
let m = Method::new("marty", MethodFlag::Static, f.clone());
|
||||
assert!(!m.is_public());
|
||||
assert!(!m.is_private());
|
||||
assert!(m.is_static());
|
||||
|
||||
let mut m = Method::new("marty", MethodFlag::Static, f.clone());
|
||||
m.set_flag(MethodFlag::Public);
|
||||
assert!(m.is_public());
|
||||
assert!(!m.is_private());
|
||||
assert!(!m.is_static());
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
mod function;
|
||||
mod method;
|
||||
mod requirement;
|
||||
mod tables;
|
||||
mod r#trait;
|
||||
pub use function::{Function, FunctionBody, FunctionClause};
|
||||
pub use method::{Method, MethodFlag};
|
||||
pub use r#trait::TraitData;
|
||||
pub use requirement::Requirement;
|
||||
use std::rc::Rc;
|
||||
pub use tables::{VTableClassData, VTableDefaultImplData, VTableImplData, VTableTraitData};
|
||||
|
||||
use crate::ClassData;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Type {
|
||||
Class(ClassData),
|
||||
Trait(TraitData),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Instance {
|
||||
class: Rc<ClassData>,
|
||||
}
|
||||
|
||||
pub trait VTable {
|
||||
fn insert_method(&mut self, method: Method) -> usize;
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use crate::vtable::Type;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Requirement(Vec<Rc<Type>>);
|
||||
|
||||
impl Requirement {
|
||||
pub fn new() -> Requirement {
|
||||
Requirement(Vec::new())
|
||||
}
|
||||
|
||||
pub fn push(&mut self, r#type: Rc<Type>) {
|
||||
self.0.push(r#type);
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
use crate::vtable::{Method, VTable};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VTableImplData(Vec<Method>);
|
||||
|
||||
impl VTableImplData {
|
||||
pub fn new() -> VTableImplData {
|
||||
VTableImplData(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VTableDefaultImplData(Vec<Method>);
|
||||
|
||||
impl VTableDefaultImplData {
|
||||
pub fn new() -> VTableDefaultImplData {
|
||||
VTableDefaultImplData(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VTableClassData(Vec<Method>);
|
||||
|
||||
impl VTableClassData {
|
||||
pub fn new() -> VTableClassData {
|
||||
VTableClassData(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VTableTraitData(Vec<Method>);
|
||||
|
||||
impl VTableTraitData {
|
||||
pub fn new() -> VTableTraitData {
|
||||
VTableTraitData(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for VTableImplData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.0.push(method);
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.0.get(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for VTableDefaultImplData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.0.push(method);
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.0.get(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for VTableClassData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.0.push(method);
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.0.get(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for VTableTraitData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.0.push(method);
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.0.get(id)
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
use crate::vtable::{Method, VTable, VTableTraitData};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TraitData {
|
||||
name: String,
|
||||
vtable: VTableTraitData,
|
||||
}
|
||||
|
||||
impl TraitData {
|
||||
pub fn new(name: &str) -> TraitData {
|
||||
TraitData {
|
||||
name: name.to_string(),
|
||||
vtable: VTableTraitData::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl VTable for TraitData {
|
||||
fn insert_method(&mut self, method: Method) -> usize {
|
||||
self.vtable.insert_method(method)
|
||||
}
|
||||
|
||||
fn get_method(&self, id: usize) -> Option<&Method> {
|
||||
self.vtable.get_method(id)
|
||||
}
|
||||
}
|
Reference in a new issue