WIP
This commit is contained in:
parent
2b2d40bb55
commit
f2b84a6e54
44 changed files with 966 additions and 834 deletions
11
huia-compiler/src/bootstrap/mod.rs
Normal file
11
huia-compiler/src/bootstrap/mod.rs
Normal file
|
@ -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"));
|
||||||
|
}
|
|
@ -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<RwLock<ClassInner>>);
|
|
||||||
|
|
||||||
#[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"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
use crate::class::{Class, ClassId};
|
|
||||||
use crate::identifier::Identifier;
|
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
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(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<ClassId> {
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
mod actual;
|
|
||||||
mod class_id;
|
|
||||||
mod classes;
|
|
||||||
pub use actual::Class;
|
|
||||||
pub use class_id::ClassId;
|
|
||||||
pub use classes::Classes;
|
|
137
huia-compiler/src/classes/actual.rs
Normal file
137
huia-compiler/src/classes/actual.rs
Normal file
|
@ -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<RwLock<ClassInner>>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ClassInner {
|
||||||
|
id: TypeId,
|
||||||
|
name: Identifier,
|
||||||
|
properties: Vec<Argument>,
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
2
huia-compiler/src/classes/mod.rs
Normal file
2
huia-compiler/src/classes/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mod actual;
|
||||||
|
pub use actual::Class;
|
|
@ -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<ConstantId> for usize {
|
|
||||||
fn from(data: ConstantId) -> usize {
|
|
||||||
data.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<usize> for ConstantId {
|
|
||||||
fn from(data: usize) -> ConstantId {
|
|
||||||
ConstantId(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Constants {
|
|
||||||
values: Vec<Constant>,
|
|
||||||
strings: StringInterner<Sym>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<i64> {
|
|
||||||
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<f64> {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +1,81 @@
|
||||||
use crate::class::{Class, Classes};
|
use crate::classes::Class;
|
||||||
use crate::constant::Constants;
|
|
||||||
use crate::function::Functions;
|
use crate::function::Functions;
|
||||||
use crate::identifier::Identifiers;
|
use crate::identifier::{Identifier, Identifiers};
|
||||||
use crate::r#trait::{Trait, Traits};
|
use crate::traits::Trait;
|
||||||
|
use crate::types::{Type, TypeId, TypeTable};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
classes: Classes,
|
types: TypeTable,
|
||||||
traits: Traits,
|
|
||||||
identifiers: Identifiers,
|
identifiers: Identifiers,
|
||||||
constants: Constants,
|
|
||||||
functions: Functions,
|
functions: Functions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new() -> Context {
|
pub fn new() -> Context {
|
||||||
Context {
|
Context {
|
||||||
classes: Classes::new(),
|
types: TypeTable::new(),
|
||||||
traits: Traits::new(),
|
|
||||||
identifiers: Identifiers::new(),
|
identifiers: Identifiers::new(),
|
||||||
constants: Constants::new(),
|
|
||||||
functions: Functions::new(),
|
functions: Functions::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_class(&mut self, name: &str) -> Class {
|
pub fn ensure_class(&self, name: Identifier) -> Class {
|
||||||
let name = self.identifiers.get(name);
|
match self.get_type_by_name(name) {
|
||||||
let id = self.classes.next_id();
|
Some(ty) => match ty.as_class() {
|
||||||
let class = Class::new(id, name);
|
Some(ty) => ty,
|
||||||
self.classes.push(class);
|
None => self.create_class(name),
|
||||||
self.classes.get(id).unwrap()
|
},
|
||||||
|
None => self.create_class(name),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_trait(&mut self, name: &str) -> Trait {
|
pub fn ensure_trait(&self, name: Identifier) -> Trait {
|
||||||
let name = self.identifiers.get(name);
|
match self.get_type_by_name(name) {
|
||||||
let id = self.traits.next_id();
|
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);
|
let tr = Trait::new(id, name);
|
||||||
self.traits.push(tr);
|
self.types.push(tr.clone());
|
||||||
self.traits.get(id).unwrap()
|
tr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type(&self, id: TypeId) -> Option<Type> {
|
||||||
|
self.types.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_by_name(&self, name: Identifier) -> Option<Type> {
|
||||||
|
self.types.find(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ident(&self, name: &str) -> Identifier {
|
||||||
|
self.identifiers().get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
// Traits and Classes must be empty if identifiers is empty because
|
self.identifiers.is_empty() && self.types.is_empty()
|
||||||
// classes and traits must be initialised with identifier names.
|
|
||||||
self.identifiers.is_empty() && self.constants.is_empty()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifiers(&self) -> &Identifiers {
|
pub fn identifiers(&self) -> &Identifiers {
|
||||||
&self.identifiers
|
&self.identifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constants(&self) -> &Constants {
|
pub fn types(&self) -> &TypeTable {
|
||||||
&self.constants
|
&self.types
|
||||||
}
|
|
||||||
|
|
||||||
pub fn classes(&self) -> &Classes {
|
|
||||||
&self.classes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn traits(&self) -> &Traits {
|
|
||||||
&self.traits
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn functions(&self) -> &Functions {
|
pub fn functions(&self) -> &Functions {
|
||||||
|
@ -73,16 +89,16 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new() {
|
fn new() {
|
||||||
let mut context = Context::new();
|
let context = Context::new();
|
||||||
let class0 = context.new_class("Marty McFly");
|
let class0 = context.ensure_class(context.ident("Marty McFly"));
|
||||||
let class1 = context.classes().get(class0.id()).unwrap();
|
let class1 = context.types().get(class0.id()).unwrap();
|
||||||
assert_eq!(class0, class1);
|
assert_eq!(class0, class1);
|
||||||
|
|
||||||
let tr0 = context.new_trait("Doc Brown");
|
let tr0 = context.ensure_trait(context.ident("Doc Brown"));
|
||||||
let tr1 = context.traits().get(tr0.id()).unwrap();
|
let tr1 = context.types().get(tr0.id()).unwrap();
|
||||||
assert_eq!(tr0, tr1);
|
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");
|
assert_eq!(context.identifiers().resolve(id).unwrap(), "Einstein Brown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::function::{Clause, ClauseId, FunctionId};
|
use crate::function::{Clause, ClauseId, FunctionId};
|
||||||
use crate::identifier::Identifier;
|
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use wrc::WRC;
|
use wrc::WRC;
|
||||||
|
|
||||||
|
@ -9,7 +8,6 @@ pub struct Function(WRC<RwLock<FunctionInner>>);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FunctionInner {
|
struct FunctionInner {
|
||||||
id: FunctionId,
|
id: FunctionId,
|
||||||
name: Identifier,
|
|
||||||
clauses: Vec<Clause>,
|
clauses: Vec<Clause>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,14 +16,6 @@ impl FunctionInner {
|
||||||
self.id
|
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 {
|
fn add_clause(&mut self, clause: Clause) -> ClauseId {
|
||||||
let idx = self.clauses.len();
|
let idx = self.clauses.len();
|
||||||
self.clauses.push(clause);
|
self.clauses.push(clause);
|
||||||
|
@ -38,9 +28,9 @@ impl FunctionInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn new(id: FunctionId, name: Identifier) -> Function {
|
pub fn new(id: FunctionId) -> Function {
|
||||||
let clauses = Vec::new();
|
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 {
|
pub fn id(&self) -> FunctionId {
|
||||||
|
@ -48,16 +38,6 @@ impl Function {
|
||||||
fun.id()
|
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 {
|
pub fn add_clause(&self, clause: Clause) -> ClauseId {
|
||||||
let mut fun = self.0.write().unwrap();
|
let mut fun = self.0.write().unwrap();
|
||||||
fun.add_clause(clause)
|
fun.add_clause(clause)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::function::{Argument, ClauseId};
|
use crate::argument::Argument;
|
||||||
|
use crate::function::ClauseId;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use wrc::WRC;
|
use wrc::WRC;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Clause(WRC<RwLock<ClauseInner>>);
|
pub struct Clause(WRC<RwLock<ClauseInner>>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::function::{Function, FunctionId};
|
use crate::function::{Function, FunctionId};
|
||||||
use crate::identifier::Identifier;
|
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
@ -30,15 +29,6 @@ impl Functions {
|
||||||
FunctionId::from(elements.len())
|
FunctionId::from(elements.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find(&self, name: Identifier) -> Option<FunctionId> {
|
|
||||||
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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
let elements = self.0.read().unwrap();
|
let elements = self.0.read().unwrap();
|
||||||
elements.is_empty()
|
elements.is_empty()
|
||||||
|
@ -48,22 +38,18 @@ impl Functions {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::identifier::Identifiers;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
let identifiers = Identifiers::new();
|
|
||||||
let mut functions = Functions::new();
|
let mut functions = Functions::new();
|
||||||
|
|
||||||
let id = functions.next_id();
|
let id = functions.next_id();
|
||||||
let name = identifiers.get("Marty McFly");
|
let function0 = Function::new(id);
|
||||||
let function0 = Function::new(id, name);
|
|
||||||
|
|
||||||
let idx = functions.push(function0);
|
let idx = functions.push(function0);
|
||||||
assert_eq!(usize::from(idx), 0);
|
assert_eq!(usize::from(idx), 0);
|
||||||
|
|
||||||
let function1 = functions.get(idx).unwrap();
|
let function1 = functions.get(idx).unwrap();
|
||||||
assert_eq!(function1.id(), id);
|
assert_eq!(function1.id(), id);
|
||||||
assert_eq!(function1.name(), identifiers.get("Marty McFly"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,9 @@ mod clause;
|
||||||
mod clause_id;
|
mod clause_id;
|
||||||
mod function_id;
|
mod function_id;
|
||||||
mod functions;
|
mod functions;
|
||||||
mod argument;
|
|
||||||
|
|
||||||
pub use actual::Function;
|
pub use actual::Function;
|
||||||
pub use clause::Clause;
|
pub use clause::Clause;
|
||||||
pub use clause_id::ClauseId;
|
pub use clause_id::ClauseId;
|
||||||
pub use function_id::FunctionId;
|
pub use function_id::FunctionId;
|
||||||
pub use functions::Functions;
|
pub use functions::Functions;
|
||||||
pub use argument::Argument;
|
|
||||||
|
|
|
@ -1 +1,12 @@
|
||||||
|
pub enum Instruction {
|
||||||
|
Noop = 0,
|
||||||
|
InvokePrimitive,
|
||||||
|
Pop,
|
||||||
|
PushFalse,
|
||||||
|
PushInteger,
|
||||||
|
PushLocal,
|
||||||
|
PushSelf,
|
||||||
|
PushTrue,
|
||||||
|
Return,
|
||||||
|
SetLocal,
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
mod class;
|
mod argument;
|
||||||
mod constant;
|
mod bootstrap;
|
||||||
|
mod classes;
|
||||||
mod context;
|
mod context;
|
||||||
mod function;
|
mod function;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod instructions;
|
mod instructions;
|
||||||
mod property_type_map;
|
mod method;
|
||||||
mod r#trait;
|
mod object;
|
||||||
mod r#type;
|
mod parse_consumer;
|
||||||
|
mod scope;
|
||||||
|
mod stack;
|
||||||
|
mod traits;
|
||||||
mod type_spec;
|
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 context::Context;
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use r#trait::{Trait, TraitId};
|
pub use object::Object;
|
||||||
pub use r#type::Type;
|
pub use traits::Trait;
|
||||||
pub use type_spec::TypeSpec;
|
pub use type_spec::TypeSpec;
|
||||||
|
pub use types::TypeId;
|
||||||
|
|
50
huia-compiler/src/method/actual.rs
Normal file
50
huia-compiler/src/method/actual.rs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
14
huia-compiler/src/method/method_id.rs
Normal file
14
huia-compiler/src/method/method_id.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct MethodId(usize);
|
||||||
|
|
||||||
|
impl From<MethodId> for usize {
|
||||||
|
fn from(data: MethodId) -> usize {
|
||||||
|
data.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for MethodId {
|
||||||
|
fn from(data: usize) -> MethodId {
|
||||||
|
MethodId(data)
|
||||||
|
}
|
||||||
|
}
|
5
huia-compiler/src/method/mod.rs
Normal file
5
huia-compiler/src/method/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod actual;
|
||||||
|
mod method_id;
|
||||||
|
|
||||||
|
pub use actual::{Flag, Method};
|
||||||
|
pub use method_id::MethodId;
|
94
huia-compiler/src/object.rs
Normal file
94
huia-compiler/src/object.rs
Normal file
|
@ -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<ObjectInner>);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd)]
|
||||||
|
struct ObjectInner {
|
||||||
|
type_id: TypeId,
|
||||||
|
value: ObjectValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd)]
|
||||||
|
pub enum ObjectValue {
|
||||||
|
Array(Vec<Object>),
|
||||||
|
Atom(Sym),
|
||||||
|
False,
|
||||||
|
Float(f64),
|
||||||
|
Integer(i64),
|
||||||
|
String(Sym),
|
||||||
|
True,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<Object>> for ObjectValue {
|
||||||
|
fn from(data: Vec<Object>) -> ObjectValue {
|
||||||
|
ObjectValue::Array(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for ObjectValue {
|
||||||
|
fn from(data: bool) -> ObjectValue {
|
||||||
|
if data {
|
||||||
|
ObjectValue::True
|
||||||
|
} else {
|
||||||
|
ObjectValue::False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for ObjectValue {
|
||||||
|
fn from(data: f64) -> ObjectValue {
|
||||||
|
ObjectValue::Float(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> 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<H: hash::Hasher>(&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::<f64, u64>(*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
|
||||||
|
}
|
||||||
|
}
|
56
huia-compiler/src/parse_consumer/definition.rs
Normal file
56
huia-compiler/src/parse_consumer/definition.rs
Normal file
|
@ -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<TypeId> 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")))
|
||||||
|
}
|
||||||
|
}
|
12
huia-compiler/src/parse_consumer/mod.rs
Normal file
12
huia-compiler/src/parse_consumer/mod.rs
Normal file
|
@ -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()),
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
use crate::identifier::Identifier;
|
|
||||||
use crate::type_spec::TypeSpec;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct PropertyTypeMap(BTreeMap<Identifier, TypeSpec>);
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
32
huia-compiler/src/scope.rs
Normal file
32
huia-compiler/src/scope.rs
Normal file
|
@ -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<Vec<(Identifier, Object)>>);
|
||||||
|
|
||||||
|
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<Object> {
|
||||||
|
let scope = self.0.write().unwrap();
|
||||||
|
match scope.iter().rev().find(|(n, _)| n == &name) {
|
||||||
|
Some((_, o)) => Some(o.clone()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
huia-compiler/src/stack.rs
Normal file
23
huia-compiler/src/stack.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Stack<T: Debug + Default>(Vec<T>);
|
||||||
|
|
||||||
|
impl<T: Debug + Default> Stack<T> {
|
||||||
|
pub fn new() -> Stack<T> {
|
||||||
|
Stack(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self) {
|
||||||
|
self.0.push(T::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
|
self.0.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current(&self) -> &T {
|
||||||
|
let idx = self.0.len() - 1;
|
||||||
|
self.0.get(idx).unwrap()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<RwLock<TraitInner>>);
|
|
||||||
|
|
||||||
#[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<T: Into<Type>>(&self, r#type: T) {
|
|
||||||
let ty: Type = r#type.into();
|
|
||||||
let mut tr = self.0.write().unwrap();
|
|
||||||
tr.requires.push(ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn requires<T: Into<Type>>(&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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
mod actual;
|
|
||||||
mod trait_id;
|
|
||||||
mod traits;
|
|
||||||
pub use actual::Trait;
|
|
||||||
pub use trait_id::TraitId;
|
|
||||||
pub use traits::Traits;
|
|
|
@ -1,14 +0,0 @@
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<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(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<TraitId> {
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
123
huia-compiler/src/traits/actual.rs
Normal file
123
huia-compiler/src/traits/actual.rs
Normal file
|
@ -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<RwLock<TraitInner>>);
|
||||||
|
|
||||||
|
#[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<T: Into<TypeId>>(&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));
|
||||||
|
}
|
||||||
|
}
|
2
huia-compiler/src/traits/mod.rs
Normal file
2
huia-compiler/src/traits/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mod actual;
|
||||||
|
pub use actual::Trait;
|
|
@ -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<ClassId> {
|
|
||||||
match self {
|
|
||||||
Type::Class(id) => Some(*id),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trait_id(&self) -> Option<TraitId> {
|
|
||||||
match self {
|
|
||||||
Type::Trait(id) => Some(*id),
|
|
||||||
_ => 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Class> for Type {
|
|
||||||
fn from(class: Class) -> Type {
|
|
||||||
Type::Class(class.id())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Trait> 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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +1,27 @@
|
||||||
use crate::r#type::Type;
|
use crate::types::TypeId;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TypeSpec(Vec<Type>);
|
pub struct TypeSpec(Vec<TypeId>);
|
||||||
|
|
||||||
impl TypeSpec {
|
impl TypeSpec {
|
||||||
pub fn new() -> TypeSpec {
|
pub fn new() -> TypeSpec {
|
||||||
TypeSpec(Vec::new())
|
TypeSpec(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, ty: Type) {
|
pub fn push(&mut self, ty: TypeId) {
|
||||||
self.0.push(ty)
|
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)
|
self.0.iter().any(|i| i == &ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<Type>> From<T> for TypeSpec {
|
impl<T: Into<TypeId>> From<T> for TypeSpec {
|
||||||
fn from(ty: T) -> TypeSpec {
|
fn from(ty: T) -> TypeSpec {
|
||||||
let ty: Type = ty.into();
|
let ty: TypeId = ty.into();
|
||||||
let mut ts = TypeSpec::new();
|
let mut ts = TypeSpec::new();
|
||||||
ts.push(ty);
|
ts.push(ty);
|
||||||
ts
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
112
huia-compiler/src/types/actual.rs
Normal file
112
huia-compiler/src/types/actual.rs
Normal file
|
@ -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<T: Into<Type>>(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<Class> {
|
||||||
|
match self {
|
||||||
|
Type::Class(t) => Some(t.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_trait(&self) -> Option<Trait> {
|
||||||
|
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<Class> for Type {
|
||||||
|
fn from(class: Class) -> Type {
|
||||||
|
Type::Class(class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Trait> 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<Class> for Type {
|
||||||
|
fn eq(&self, other: &Class) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::Class(c) => c.id() == other.id(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Trait> for Type {
|
||||||
|
fn eq(&self, other: &Trait) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::Trait(c) => c.id() == other.id(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Type> for Trait {
|
||||||
|
fn eq(&self, other: &Type) -> bool {
|
||||||
|
match other {
|
||||||
|
Type::Trait(c) => c.id() == self.id(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Type> for Class {
|
||||||
|
fn eq(&self, other: &Type) -> bool {
|
||||||
|
match other {
|
||||||
|
Type::Class(c) => c.id() == self.id(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
huia-compiler/src/types/mod.rs
Normal file
6
huia-compiler/src/types/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
mod actual;
|
||||||
|
mod type_id;
|
||||||
|
mod table;
|
||||||
|
pub use actual::Type;
|
||||||
|
pub use type_id::TypeId;
|
||||||
|
pub use table::TypeTable;
|
45
huia-compiler/src/types/table.rs
Normal file
45
huia-compiler/src/types/table.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::identifier::Identifier;
|
||||||
|
use crate::types::{Type, TypeId};
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct TypeTable(RwLock<Vec<Type>>);
|
||||||
|
|
||||||
|
impl TypeTable {
|
||||||
|
pub fn new() -> TypeTable {
|
||||||
|
TypeTable(RwLock::new(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push<T: Into<Type>>(&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<Type> {
|
||||||
|
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<Type> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
29
huia-compiler/src/types/type_id.rs
Normal file
29
huia-compiler/src/types/type_id.rs
Normal file
|
@ -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<Class> for TypeId {
|
||||||
|
fn from(cl: Class) -> TypeId {
|
||||||
|
cl.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Trait> for TypeId {
|
||||||
|
fn from(tr: Trait) -> TypeId {
|
||||||
|
tr.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TypeId> for usize {
|
||||||
|
fn from(id: TypeId) -> usize {
|
||||||
|
id.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for TypeId {
|
||||||
|
fn from(id: usize) -> TypeId {
|
||||||
|
TypeId(id)
|
||||||
|
}
|
||||||
|
}
|
31
huia-compiler/src/vtable.rs
Normal file
31
huia-compiler/src/vtable.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use crate::method::{Method, MethodId};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct VTable(Vec<Method>);
|
||||||
|
|
||||||
|
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<Method> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,6 @@ mod test {
|
||||||
.next()
|
.next()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let float = Float::from(pair);
|
let float = Float::from(pair);
|
||||||
assert_eq!(float.value(), 123.456);
|
assert!(float.value() - 123.456 < std::f64::EPSILON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
mod atom;
|
mod atom;
|
||||||
mod binary;
|
mod binary;
|
||||||
mod boolean;
|
mod boolean;
|
||||||
mod constant;
|
|
||||||
mod float;
|
mod float;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod integer;
|
mod integer;
|
||||||
mod local;
|
mod local;
|
||||||
mod string;
|
mod string;
|
||||||
mod term;
|
mod term;
|
||||||
|
mod typename;
|
||||||
mod unary;
|
mod unary;
|
||||||
|
|
||||||
pub use atom::Atom;
|
pub use atom::Atom;
|
||||||
pub use binary::Binary;
|
pub use binary::Binary;
|
||||||
pub use boolean::Boolean;
|
pub use boolean::Boolean;
|
||||||
pub use constant::Constant;
|
|
||||||
pub use float::Float;
|
pub use float::Float;
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use integer::Integer;
|
pub use integer::Integer;
|
||||||
pub use local::Local;
|
pub use local::Local;
|
||||||
pub use string::String;
|
pub use string::String;
|
||||||
pub use term::{NodeType, Term};
|
pub use term::{NodeType, Term};
|
||||||
|
pub use typename::Type;
|
||||||
pub use unary::Unary;
|
pub use unary::Unary;
|
||||||
|
|
||||||
use crate::input_location::InputLocation;
|
use crate::input_location::InputLocation;
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub enum NodeType {
|
||||||
Binary,
|
Binary,
|
||||||
Boolean,
|
Boolean,
|
||||||
Call,
|
Call,
|
||||||
Constant,
|
Type,
|
||||||
Constructor,
|
Constructor,
|
||||||
Declaration,
|
Declaration,
|
||||||
Definition,
|
Definition,
|
||||||
|
@ -43,8 +43,8 @@ enum Inner {
|
||||||
Binary(Binary, Box<Term>, Box<Term>),
|
Binary(Binary, Box<Term>, Box<Term>),
|
||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
Call(Identifier, Vec<Term>),
|
Call(Identifier, Vec<Term>),
|
||||||
Constant(Constant),
|
Type(Type),
|
||||||
Constructor(Constant, Vec<(Identifier, Term)>),
|
Constructor(Type, Vec<(Identifier, Term)>),
|
||||||
Declaration(Identifier, Box<Term>),
|
Declaration(Identifier, Box<Term>),
|
||||||
Definition(
|
Definition(
|
||||||
Identifier,
|
Identifier,
|
||||||
|
@ -68,9 +68,8 @@ impl Term {
|
||||||
match result {
|
match result {
|
||||||
Ok(pairs) => {
|
Ok(pairs) => {
|
||||||
let terms: Vec<Term> = pairs
|
let terms: Vec<Term> = pairs
|
||||||
.into_iter()
|
|
||||||
.take_while(|pair| pair.as_rule() != Rule::EOI)
|
.take_while(|pair| pair.as_rule() != Rule::EOI)
|
||||||
.map(|pair| Term::from(pair))
|
.map(Term::from)
|
||||||
.collect();
|
.collect();
|
||||||
Ok(terms)
|
Ok(terms)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,7 @@ impl Term {
|
||||||
Inner::Boolean(_) => NodeType::Boolean,
|
Inner::Boolean(_) => NodeType::Boolean,
|
||||||
Inner::Binary(_, _, _) => NodeType::Binary,
|
Inner::Binary(_, _, _) => NodeType::Binary,
|
||||||
Inner::Call(_, _) => NodeType::Call,
|
Inner::Call(_, _) => NodeType::Call,
|
||||||
Inner::Constant(_) => NodeType::Constant,
|
Inner::Type(_) => NodeType::Type,
|
||||||
Inner::Constructor(_, _) => NodeType::Constructor,
|
Inner::Constructor(_, _) => NodeType::Constructor,
|
||||||
Inner::Definition(_, _, _, _, _) => NodeType::Definition,
|
Inner::Definition(_, _, _, _, _) => NodeType::Definition,
|
||||||
Inner::Declaration(_, _) => NodeType::Declaration,
|
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 {
|
match self.inner {
|
||||||
Inner::Constant(ref node) => Some(node),
|
Inner::Type(ref node) => Some(node),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constructor(&self) -> Option<(&Constant, &Vec<(Identifier, Term)>)> {
|
pub fn constructor(&self) -> Option<(&Type, &Vec<(Identifier, Term)>)> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Inner::Constructor(ref constant, ref properties) => Some((constant, properties)),
|
Inner::Constructor(ref typename, ref properties) => Some((typename, properties)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +242,7 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
Rule::array => {
|
Rule::array => {
|
||||||
let mut result = Vec::new();
|
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));
|
result.push(Term::from(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +263,7 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
let mut inner = pair.clone().into_inner();
|
let mut inner = pair.clone().into_inner();
|
||||||
let name = Identifier::from(inner.next().unwrap());
|
let name = Identifier::from(inner.next().unwrap());
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
for argument in inner.into_iter() {
|
for argument in inner {
|
||||||
match argument.as_rule() {
|
match argument.as_rule() {
|
||||||
Rule::call_argument => {
|
Rule::call_argument => {
|
||||||
args.push(Term::from(argument.into_inner().next().unwrap()))
|
args.push(Term::from(argument.into_inner().next().unwrap()))
|
||||||
|
@ -277,16 +276,16 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
inner: Inner::Call(name, args),
|
inner: Inner::Call(name, args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rule::constant => Term {
|
Rule::typename => Term {
|
||||||
location: InputLocation::from(pair.clone()),
|
location: InputLocation::from(pair.clone()),
|
||||||
inner: Inner::Constant(Constant::from(pair)),
|
inner: Inner::Type(Type::from(pair)),
|
||||||
},
|
},
|
||||||
Rule::constructor => {
|
Rule::constructor => {
|
||||||
let mut inner = pair.clone().into_inner();
|
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();
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
for property in inner.into_iter() {
|
for property in inner {
|
||||||
match property.as_rule() {
|
match property.as_rule() {
|
||||||
Rule::constructor_property => {
|
Rule::constructor_property => {
|
||||||
let mut proppairs = property.into_inner();
|
let mut proppairs = property.into_inner();
|
||||||
|
@ -300,7 +299,7 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
|
|
||||||
Term {
|
Term {
|
||||||
location: InputLocation::from(pair),
|
location: InputLocation::from(pair),
|
||||||
inner: Inner::Constructor(constant, properties),
|
inner: Inner::Constructor(typename, properties),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rule::declaration => {
|
Rule::declaration => {
|
||||||
|
@ -329,49 +328,43 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
|
|
||||||
let mut typeargs = Vec::new();
|
let mut typeargs = Vec::new();
|
||||||
|
|
||||||
match typeargspair.next() {
|
if let Some(arguments) = typeargspair.next() {
|
||||||
Some(arguments) => {
|
for argument in arguments.into_inner() {
|
||||||
for argument in arguments.into_inner().into_iter() {
|
let mut argument = argument.into_inner();
|
||||||
let mut argument = argument.into_inner();
|
let argname = Identifier::from(argument.next().unwrap());
|
||||||
let argname = Identifier::from(argument.next().unwrap());
|
let argvalue = Term::from(argument.next().unwrap());
|
||||||
let argvalue = Term::from(argument.next().unwrap());
|
typeargs.push((argname, argvalue));
|
||||||
typeargs.push((argname, argvalue));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut requirements = Vec::new();
|
let mut requirements = Vec::new();
|
||||||
|
|
||||||
match typeargspair.next() {
|
if let Some(requirement) = typeargspair.next() {
|
||||||
Some(requirement) => match requirement.as_rule() {
|
match requirement.as_rule() {
|
||||||
Rule::definition_requirement => {
|
Rule::definition_requirement => {
|
||||||
for constant in requirement.clone().into_inner().into_iter() {
|
for typename in requirement.clone().into_inner() {
|
||||||
let constant = Term::from(constant);
|
let typename = Term::from(typename);
|
||||||
requirements.push(constant);
|
requirements.push(typename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!("Expected pair to be a Requirement"),
|
_ => unreachable!("Expected pair to be a Requirement"),
|
||||||
},
|
}
|
||||||
None => (),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let mut bodyargs = Vec::new();
|
let mut bodyargs = Vec::new();
|
||||||
|
|
||||||
match inner.next() {
|
if let Some(arguments) = inner.next() {
|
||||||
Some(arguments) => {
|
for argument in arguments.into_inner() {
|
||||||
for argument in arguments.into_inner().into_iter() {
|
let mut arg_inner = argument.into_inner();
|
||||||
let mut arg_inner = argument.into_inner();
|
let argname = Identifier::from(arg_inner.next().unwrap());
|
||||||
let argname = Identifier::from(arg_inner.next().unwrap());
|
let mut body: Vec<Term> = vec![];
|
||||||
let mut body: Vec<Term> = vec![];
|
for argvalue in arg_inner {
|
||||||
for argvalue in arg_inner.into_iter() {
|
body.push(Term::from(argvalue));
|
||||||
body.push(Term::from(argvalue));
|
|
||||||
}
|
|
||||||
bodyargs.push((argname, body));
|
|
||||||
}
|
}
|
||||||
|
bodyargs.push((argname, body));
|
||||||
}
|
}
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Term {
|
Term {
|
||||||
location: InputLocation::from(pair),
|
location: InputLocation::from(pair),
|
||||||
inner: Inner::Definition(
|
inner: Inner::Definition(
|
||||||
|
@ -399,7 +392,7 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
Rule::map => {
|
Rule::map => {
|
||||||
let mut contents = Vec::new();
|
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 mut inner = map_pair.into_inner();
|
||||||
let keypair = inner.next().unwrap();
|
let keypair = inner.next().unwrap();
|
||||||
let key = match keypair.as_rule() {
|
let key = match keypair.as_rule() {
|
||||||
|
@ -424,7 +417,7 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
let mut call = inner.next().unwrap().into_inner();
|
let mut call = inner.next().unwrap().into_inner();
|
||||||
let name = Identifier::from(call.next().unwrap());
|
let name = Identifier::from(call.next().unwrap());
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
for argument in call.into_iter() {
|
for argument in call {
|
||||||
match argument.as_rule() {
|
match argument.as_rule() {
|
||||||
Rule::call_argument => {
|
Rule::call_argument => {
|
||||||
args.push(Term::from(argument.into_inner().next().unwrap()))
|
args.push(Term::from(argument.into_inner().next().unwrap()))
|
||||||
|
@ -541,8 +534,8 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_constant() {
|
fn test_constant() {
|
||||||
let terms = Term::input("Marty").unwrap();
|
let terms = Term::input("Marty").unwrap();
|
||||||
assert_eq!(terms[0].node_type(), NodeType::Constant);
|
assert_eq!(terms[0].node_type(), NodeType::Type);
|
||||||
let term = terms[0].constant().unwrap().clone();
|
let term = terms[0].typename().unwrap().clone();
|
||||||
assert_eq!(term.value(), "Marty");
|
assert_eq!(term.value(), "Marty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,16 +543,16 @@ mod test {
|
||||||
fn test_constructor_empty() {
|
fn test_constructor_empty() {
|
||||||
let terms = Term::input("Character {}").unwrap();
|
let terms = Term::input("Character {}").unwrap();
|
||||||
assert_eq!(terms[0].node_type(), NodeType::Constructor);
|
assert_eq!(terms[0].node_type(), NodeType::Constructor);
|
||||||
let (constant, properties) = terms[0].constructor().unwrap();
|
let (typename, properties) = terms[0].constructor().unwrap();
|
||||||
assert_eq!(constant.value_ref(), "Character");
|
assert_eq!(typename.value_ref(), "Character");
|
||||||
assert_eq!(properties.len(), 0);
|
assert_eq!(properties.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_constructor() {
|
fn test_constructor() {
|
||||||
let terms = Term::input("Character { name: \"Marty McFly\" }").unwrap();
|
let terms = Term::input("Character { name: \"Marty McFly\" }").unwrap();
|
||||||
let (constant, properties) = terms[0].constructor().unwrap();
|
let (typename, properties) = terms[0].constructor().unwrap();
|
||||||
assert_eq!(constant.value_ref(), "Character");
|
assert_eq!(typename.value_ref(), "Character");
|
||||||
assert_eq!(properties.len(), 1);
|
assert_eq!(properties.len(), 1);
|
||||||
let (key, value) = &properties[0];
|
let (key, value) = &properties[0];
|
||||||
assert_eq!(key.value_ref(), "name");
|
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();
|
let terms = Term::input("type Delorean(speed: Integer) do\n123\n\n456\nend").unwrap();
|
||||||
assert_eq!(terms[0].node_type(), NodeType::Definition);
|
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!(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];
|
let (argname, argvalue) = &args[0];
|
||||||
assert_eq!(argname.value_ref(), "speed");
|
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];
|
let (argname, argvalues) = &body[0];
|
||||||
assert_eq!(argname.value_ref(), "do");
|
assert_eq!(argname.value_ref(), "do");
|
||||||
|
@ -589,9 +582,9 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_definition_empty() {
|
fn test_definition_empty() {
|
||||||
let terms = Term::input("type Delorean").unwrap();
|
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!(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!(args.len(), 0);
|
||||||
assert_eq!(body.len(), 0);
|
assert_eq!(body.len(), 0);
|
||||||
}
|
}
|
||||||
|
@ -599,7 +592,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_definition_empty_fun() {
|
fn test_definition_empty_fun() {
|
||||||
let terms = Term::input("def hello()").unwrap();
|
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!(deftype.value_ref(), "def");
|
||||||
assert_eq!(defname.atom().unwrap().value_ref(), "hello");
|
assert_eq!(defname.atom().unwrap().value_ref(), "hello");
|
||||||
assert_eq!(args.len(), 0);
|
assert_eq!(args.len(), 0);
|
||||||
|
@ -609,7 +602,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_definition_fun() {
|
fn test_definition_fun() {
|
||||||
let terms = Term::input("def example(a: Integer, b: Atom), do: 123").unwrap();
|
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!(deftype.value_ref(), "def");
|
||||||
assert_eq!(defname.atom().unwrap().value_ref(), "example");
|
assert_eq!(defname.atom().unwrap().value_ref(), "example");
|
||||||
assert_eq!(args.len(), 2);
|
assert_eq!(args.len(), 2);
|
||||||
|
@ -619,27 +612,27 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_definition_fun_w_return_type() {
|
fn test_definition_fun_w_return_type() {
|
||||||
let terms = Term::input("def example(a: Integer, b: Atom): Integer, do: 123").unwrap();
|
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!(deftype.value_ref(), "def");
|
||||||
assert_eq!(defname.atom().unwrap().value_ref(), "example");
|
assert_eq!(defname.atom().unwrap().value_ref(), "example");
|
||||||
assert_eq!(args.len(), 2);
|
assert_eq!(args.len(), 2);
|
||||||
assert_eq!(body.len(), 1);
|
assert_eq!(body.len(), 1);
|
||||||
assert_eq!(reqs[0].constant().unwrap().value_ref(), "Integer");
|
assert_eq!(reqs[0].typename().unwrap().value_ref(), "Integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_definition_trait_with_bounds() {
|
fn test_definition_trait_with_bounds() {
|
||||||
let terms = Term::input("trait Integer: Add + Subtract + Divide + Multiply").unwrap();
|
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!(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!(args.len(), 0);
|
||||||
assert_eq!(body.len(), 0);
|
assert_eq!(body.len(), 0);
|
||||||
assert_eq!(reqs.len(), 4);
|
assert_eq!(reqs.len(), 4);
|
||||||
assert_eq!(reqs[0].constant().unwrap().value_ref(), "Add");
|
assert_eq!(reqs[0].typename().unwrap().value_ref(), "Add");
|
||||||
assert_eq!(reqs[1].constant().unwrap().value_ref(), "Subtract");
|
assert_eq!(reqs[1].typename().unwrap().value_ref(), "Subtract");
|
||||||
assert_eq!(reqs[2].constant().unwrap().value_ref(), "Divide");
|
assert_eq!(reqs[2].typename().unwrap().value_ref(), "Divide");
|
||||||
assert_eq!(reqs[3].constant().unwrap().value_ref(), "Multiply");
|
assert_eq!(reqs[3].typename().unwrap().value_ref(), "Multiply");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -658,7 +651,7 @@ mod test {
|
||||||
let terms = Term::input("1.23").unwrap();
|
let terms = Term::input("1.23").unwrap();
|
||||||
assert_eq!(terms[0].node_type(), NodeType::Float);
|
assert_eq!(terms[0].node_type(), NodeType::Float);
|
||||||
let node = terms[0].float().unwrap();
|
let node = terms[0].float().unwrap();
|
||||||
assert_eq!(node.value_ref(), &1.23);
|
assert!(node.value_ref() - 1.23 < std::f64::EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -760,7 +753,7 @@ mod test {
|
||||||
let terms = Term::input("My.Greeter.hello()").unwrap();
|
let terms = Term::input("My.Greeter.hello()").unwrap();
|
||||||
let (method_name, receiver, arguments) = terms[0].method_call().unwrap();
|
let (method_name, receiver, arguments) = terms[0].method_call().unwrap();
|
||||||
assert_eq!(method_name.value_ref(), "hello");
|
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);
|
assert_eq!(arguments.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,18 @@ use crate::input_location::InputLocation;
|
||||||
use pest::iterators::Pair;
|
use pest::iterators::Pair;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Constant {
|
pub struct Type {
|
||||||
value: String,
|
value: String,
|
||||||
location: InputLocation,
|
location: InputLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constant {
|
impl Type {
|
||||||
pub fn value(&self) -> &str {
|
pub fn value(&self) -> &str {
|
||||||
&self.value
|
&self.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value for Constant {
|
impl Value for Type {
|
||||||
type Item = String;
|
type Item = String;
|
||||||
|
|
||||||
fn value(self) -> Self::Item {
|
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 {
|
fn location(&self) -> &InputLocation {
|
||||||
&self.location
|
&self.location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<Pair<'a, Rule>> for Constant {
|
impl<'a> From<Pair<'a, Rule>> for Type {
|
||||||
fn from(pair: Pair<'a, Rule>) -> Self {
|
fn from(pair: Pair<'a, Rule>) -> Self {
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
Rule::constant => {
|
Rule::typename => {
|
||||||
let value = pair.clone().into_span().as_str().to_string();
|
let value = pair.clone().into_span().as_str().to_string();
|
||||||
Constant {
|
Type {
|
||||||
value: value,
|
value: value,
|
||||||
location: InputLocation::from(pair.into_span()),
|
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]
|
#[test]
|
||||||
fn it_parses() {
|
fn it_parses() {
|
||||||
let pair = Grammar::parse(Rule::constant, "Marty.McFly")
|
let pair = Grammar::parse(Rule::typename, "Marty.McFly")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.next()
|
.next()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let constant = Constant::from(pair);
|
let r#type = Type::from(pair);
|
||||||
assert_eq!(constant.value(), "Marty.McFly");
|
assert_eq!(r#type.value(), "Marty.McFly");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,23 +20,23 @@ call_arguments = _{ "(" ~ (call_argument ~ ("," ~ call_argument)* )? ~ ")" }
|
||||||
call_argument = { expression }
|
call_argument = { expression }
|
||||||
|
|
||||||
definition = { ident ~ definition_what ~ arguments }
|
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_arguments = { ("(" ~ (definition_argument ~ ("," ~ definition_argument)* )? ~ ")")? }
|
||||||
definition_requirement_opt = _{ (":" ~ definition_requirement)? }
|
definition_requirement_opt = _{ (":" ~ definition_requirement)? }
|
||||||
definition_requirement = { constant ~ ("+" ~ constant)* }
|
definition_requirement = { typename ~ ("+" ~ typename)* }
|
||||||
definition_argument = { keyword ~ constant }
|
definition_argument = { keyword ~ typename }
|
||||||
|
|
||||||
arguments = { argument* }
|
arguments = { argument* }
|
||||||
argument = { argument_block | argument_short }
|
argument = { argument_block | argument_short }
|
||||||
argument_block = _{ ident ~ expression* ~ "end" }
|
argument_block = _{ ident ~ expression* ~ "end" }
|
||||||
argument_short = _{ "," ~ keyword ~ expression }
|
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' | "_")* }
|
ident = @{ !reserved ~ 'a'..'z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
||||||
keyword = @{ ident ~ ":" }
|
keyword = @{ ident ~ ":" }
|
||||||
|
|
||||||
constructor = { constant ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" }
|
constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" }
|
||||||
constructor_property = { keyword ~ expression }
|
constructor_property = { keyword ~ expression }
|
||||||
|
|
||||||
map = { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" }
|
map = { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" }
|
||||||
|
@ -46,8 +46,8 @@ array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" }
|
||||||
|
|
||||||
atom = @{ ":" ~ ident }
|
atom = @{ ":" ~ ident }
|
||||||
|
|
||||||
constant = @{ constant_name ~ ("." ~ constant_name)* }
|
typename = @{ typename_name ~ ("." ~ typename_name)* }
|
||||||
constant_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
typename_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
||||||
|
|
||||||
float = ${ float_characteristic ~ "." ~ float_mantissa }
|
float = ${ float_characteristic ~ "." ~ float_mantissa }
|
||||||
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }
|
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }
|
||||||
|
|
|
@ -33,11 +33,11 @@ fn build_precedence_climber() -> PrecClimber<Rule> {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
let binary = Binary::from(op);
|
||||||
Term::create_infix(binary, lhs, rhs)
|
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)
|
PREC_CLIMBER.climb(pair.into_inner(), Term::from, build_binary)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue