Add type, trait and impl definitions.
This commit is contained in:
parent
f6359f4245
commit
292fdb1305
3 changed files with 118 additions and 31 deletions
|
@ -1,12 +1,19 @@
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::ir::{Val, IR};
|
use crate::ir::{Val, IR};
|
||||||
|
use crate::ty::TyIdx;
|
||||||
use huia_parser::ast::{Location, NodeType, Term, Value};
|
use huia_parser::ast::{Location, NodeType, Term, Value};
|
||||||
|
|
||||||
/// The Builder is a simple stack machine for converting AST into IR.
|
/// The Builder is a simple stack machine for converting AST into IR.
|
||||||
#[derive(Default)]
|
/// FIXME:
|
||||||
|
/// Maybe push a named scope somehow when defining types so that we can figure
|
||||||
|
/// out where we are when building methods, etc.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
struct Builder {
|
struct Builder {
|
||||||
/// The IR stack - used to compose intermediate values.
|
/// The IR stack - used to compose intermediate values.
|
||||||
stack: Vec<IR>,
|
ir_stack: Vec<IR>,
|
||||||
|
|
||||||
|
/// Type stack - used to track which type is currently being defined.
|
||||||
|
ty_stack: Vec<TyIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
|
@ -20,41 +27,41 @@ impl Builder {
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
let idx = context.constant_string(node.atom().unwrap().value_ref().as_str());
|
let idx = context.constant_string(node.atom().unwrap().value_ref().as_str());
|
||||||
self.stack.push(IR::Constant(ty, Val::Atom(idx)));
|
self.push_ir(IR::Constant(ty, Val::Atom(idx)));
|
||||||
}
|
}
|
||||||
NodeType::Boolean => {
|
NodeType::Boolean => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.Boolean");
|
let ty_idx = context.constant_string("Huia.Native.Boolean");
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
let value = *node.boolean().unwrap().value_ref();
|
let value = *node.boolean().unwrap().value_ref();
|
||||||
self.stack.push(IR::Constant(ty, Val::Boolean(value)));
|
self.push_ir(IR::Constant(ty, Val::Boolean(value)));
|
||||||
}
|
}
|
||||||
NodeType::Float => {
|
NodeType::Float => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.Float");
|
let ty_idx = context.constant_string("Huia.Native.Float");
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
let value = *node.float().unwrap().value_ref();
|
let value = *node.float().unwrap().value_ref();
|
||||||
self.stack.push(IR::Constant(ty, Val::Float(value)));
|
self.push_ir(IR::Constant(ty, Val::Float(value)));
|
||||||
}
|
}
|
||||||
NodeType::Integer => {
|
NodeType::Integer => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.Integer");
|
let ty_idx = context.constant_string("Huia.Native.Integer");
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
let value = *node.integer().unwrap().value_ref();
|
let value = *node.integer().unwrap().value_ref();
|
||||||
self.stack.push(IR::Constant(ty, Val::Integer(value)));
|
self.push_ir(IR::Constant(ty, Val::Integer(value)));
|
||||||
}
|
}
|
||||||
NodeType::String => {
|
NodeType::String => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.String");
|
let ty_idx = context.constant_string("Huia.Native.String");
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
let idx = context.constant_string(node.string().unwrap().value_ref().as_str());
|
let idx = context.constant_string(node.string().unwrap().value_ref().as_str());
|
||||||
self.stack.push(IR::Constant(ty, Val::String(idx)));
|
self.push_ir(IR::Constant(ty, Val::String(idx)));
|
||||||
}
|
}
|
||||||
NodeType::Ty => {
|
NodeType::Ty => {
|
||||||
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
|
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
|
||||||
let location = context.location(&node.location());
|
let location = context.location(&node.location());
|
||||||
let ty = context.reference_type(&ty_idx, location);
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
self.stack.push(IR::TypeReference(ty));
|
self.push_ir(IR::TypeReference(ty));
|
||||||
}
|
}
|
||||||
NodeType::Array => {
|
NodeType::Array => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.Array");
|
let ty_idx = context.constant_string("Huia.Native.Array");
|
||||||
|
@ -67,10 +74,10 @@ impl Builder {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| {
|
.map(|node| {
|
||||||
self.build(node.clone(), &mut context);
|
self.build(node.clone(), &mut context);
|
||||||
self.pop().unwrap()
|
self.pop_ir().unwrap()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.stack.push(IR::Constant(ty, Val::Array(elements)));
|
self.push_ir(IR::Constant(ty, Val::Array(elements)));
|
||||||
}
|
}
|
||||||
NodeType::Map => {
|
NodeType::Map => {
|
||||||
let ty_idx = context.constant_string("Huia.Native.Map");
|
let ty_idx = context.constant_string("Huia.Native.Map");
|
||||||
|
@ -83,22 +90,21 @@ impl Builder {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
self.build(key.clone(), &mut context);
|
self.build(key.clone(), &mut context);
|
||||||
let key = self.pop().unwrap();
|
let key = self.pop_ir().unwrap();
|
||||||
self.build(value.clone(), &mut context);
|
self.build(value.clone(), &mut context);
|
||||||
let value = self.pop().unwrap();
|
let value = self.pop_ir().unwrap();
|
||||||
(key, value)
|
(key, value)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.stack.push(IR::Constant(ty, Val::Map(elements)));
|
self.push_ir(IR::Constant(ty, Val::Map(elements)));
|
||||||
}
|
}
|
||||||
NodeType::Binary => {
|
NodeType::Binary => {
|
||||||
let (op, lhs, rhs) = node.binary().unwrap();
|
let (op, lhs, rhs) = node.binary().unwrap();
|
||||||
self.build(lhs.clone(), &mut context);
|
self.build(lhs.clone(), &mut context);
|
||||||
self.build(rhs.clone(), &mut context);
|
self.build(rhs.clone(), &mut context);
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop_ir().unwrap();
|
||||||
let lhs = self.pop().unwrap();
|
let lhs = self.pop_ir().unwrap();
|
||||||
self.stack
|
self.push_ir(IR::Infix(op.value_ref().clone(), Box::new((lhs, rhs))));
|
||||||
.push(IR::Infix(op.value_ref().clone(), Box::new((lhs, rhs))));
|
|
||||||
}
|
}
|
||||||
NodeType::Constructor => {
|
NodeType::Constructor => {
|
||||||
let (ty, props) = node.constructor().unwrap();
|
let (ty, props) = node.constructor().unwrap();
|
||||||
|
@ -111,18 +117,17 @@ impl Builder {
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
let key = context.constant_string(key.value_ref().as_str());
|
let key = context.constant_string(key.value_ref().as_str());
|
||||||
self.build(value.clone(), &mut context);
|
self.build(value.clone(), &mut context);
|
||||||
let value = self.stack.pop().unwrap();
|
let value = self.ir_stack.pop().unwrap();
|
||||||
(key, value)
|
(key, value)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.stack.push(IR::Constructor(ty, elements));
|
self.push_ir(IR::Constructor(ty, elements));
|
||||||
}
|
}
|
||||||
NodeType::Unary => {
|
NodeType::Unary => {
|
||||||
let (op, rhs) = node.unary().unwrap();
|
let (op, rhs) = node.unary().unwrap();
|
||||||
self.build(rhs.clone(), &mut context);
|
self.build(rhs.clone(), &mut context);
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop_ir().unwrap();
|
||||||
self.stack
|
self.push_ir(IR::Unary(op.value_ref().clone(), Box::new(rhs)));
|
||||||
.push(IR::Unary(op.value_ref().clone(), Box::new(rhs)));
|
|
||||||
}
|
}
|
||||||
NodeType::Call => {
|
NodeType::Call => {
|
||||||
let (name, args) = node.call().unwrap();
|
let (name, args) = node.call().unwrap();
|
||||||
|
@ -132,18 +137,18 @@ impl Builder {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| {
|
.map(|node| {
|
||||||
self.build(node.clone(), &mut context);
|
self.build(node.clone(), &mut context);
|
||||||
self.pop().unwrap()
|
self.pop_ir().unwrap()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.stack.push(IR::Call(name, elements));
|
self.push_ir(IR::Call(name, elements));
|
||||||
}
|
}
|
||||||
NodeType::Declaration => {
|
NodeType::Declaration => {
|
||||||
let (name, node) = node.declaration().unwrap();
|
let (name, node) = node.declaration().unwrap();
|
||||||
let name = context.constant_string(name.value_ref().as_str());
|
let name = context.constant_string(name.value_ref().as_str());
|
||||||
self.build(node.clone(), &mut context);
|
self.build(node.clone(), &mut context);
|
||||||
let node = self.pop().unwrap();
|
let node = self.pop_ir().unwrap();
|
||||||
self.stack.push(IR::Declaration(name, Box::new(node)));
|
self.push_ir(IR::Declaration(name, Box::new(node)));
|
||||||
}
|
}
|
||||||
NodeType::TypeDef => {
|
NodeType::TypeDef => {
|
||||||
let (ty, properties, body) = node.typedef().unwrap();
|
let (ty, properties, body) = node.typedef().unwrap();
|
||||||
|
@ -169,12 +174,15 @@ impl Builder {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let ty = context.declare_type(&ty_idx, properties, location);
|
||||||
|
self.push_ty(ty.clone());
|
||||||
|
|
||||||
for node in body {
|
for node in body {
|
||||||
self.build(node.clone(), &mut context);
|
self.build(node.clone(), &mut context);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = context.declare_type(&ty_idx, properties, location);
|
self.pop_ty();
|
||||||
self.stack.push(IR::TypeDefinition(ty));
|
self.push_ir(IR::TypeDefinition(ty));
|
||||||
}
|
}
|
||||||
NodeType::TraitDef => {
|
NodeType::TraitDef => {
|
||||||
let (ty, typespec, body) = node.traitdef().unwrap();
|
let (ty, typespec, body) = node.traitdef().unwrap();
|
||||||
|
@ -196,19 +204,59 @@ impl Builder {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ty = context.declare_trait(&ty_idx, types, location);
|
||||||
|
self.push_ty(ty.clone());
|
||||||
|
|
||||||
for node in body {
|
for node in body {
|
||||||
self.build(node.clone(), &mut context);
|
self.build(node.clone(), &mut context);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = context.declare_trait(&ty_idx, types, location);
|
self.pop_ty();
|
||||||
self.stack.push(IR::TraitDefinition(ty));
|
self.push_ir(IR::TraitDefinition(ty));
|
||||||
|
}
|
||||||
|
NodeType::ImplDef => {
|
||||||
|
let (ty, body) = node.impldef().unwrap();
|
||||||
|
let ty_idx = context.constant_string(ty.value_ref().as_str());
|
||||||
|
let location = context.location(&node.location());
|
||||||
|
let ty = context.reference_type(&ty_idx, location);
|
||||||
|
|
||||||
|
// the parser state should stop us from being in an
|
||||||
|
// implementation whilst not inside a type definition.
|
||||||
|
let current_type = self.peek_ty().unwrap().clone();
|
||||||
|
|
||||||
|
for node in body {
|
||||||
|
self.build(node.clone(), &mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.push_ir(IR::ImplementTrait(current_type, ty));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Option<IR> {
|
pub fn pop(&mut self) -> Option<IR> {
|
||||||
self.stack.pop()
|
self.pop_ir()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_ir(&mut self, ir: IR) {
|
||||||
|
self.ir_stack.push(ir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_ir(&mut self) -> Option<IR> {
|
||||||
|
self.ir_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_ty(&mut self, ty: TyIdx) {
|
||||||
|
self.ty_stack.push(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_ty(&mut self) -> Option<TyIdx> {
|
||||||
|
self.ty_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_ty(&self) -> Option<&TyIdx> {
|
||||||
|
let len = self.ty_stack.len();
|
||||||
|
self.ty_stack.get(len - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,4 +404,27 @@ mod test {
|
||||||
assert!(ir.is_trait_definition());
|
assert!(ir.is_trait_definition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trait_implementation() {
|
||||||
|
let term = Term::file(
|
||||||
|
r#"
|
||||||
|
type Delorean(speed: Integer) do
|
||||||
|
impl TimeMachine
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap()[0]
|
||||||
|
.clone();
|
||||||
|
let mut builder = Builder::default();
|
||||||
|
let mut context = Context::test();
|
||||||
|
builder.build(term, &mut context);
|
||||||
|
|
||||||
|
// The type definition is pushed onto the stack last.
|
||||||
|
let ir = builder.pop().unwrap();
|
||||||
|
assert!(ir.is_type_definition());
|
||||||
|
|
||||||
|
let ir = builder.pop().unwrap();
|
||||||
|
assert!(ir.is_trait_implementation());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ use huia_parser::ast::binary::Operator as BinOp;
|
||||||
use huia_parser::ast::unary::Operator as UnOp;
|
use huia_parser::ast::unary::Operator as UnOp;
|
||||||
|
|
||||||
/// Describes the intermediate representation as converted from the Parser's AST.
|
/// Describes the intermediate representation as converted from the Parser's AST.
|
||||||
|
///
|
||||||
|
/// FIXME:
|
||||||
|
/// IR should have a location too if possible.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IR {
|
pub enum IR {
|
||||||
Constant(TyIdx, Val),
|
Constant(TyIdx, Val),
|
||||||
|
@ -17,6 +20,7 @@ pub enum IR {
|
||||||
Declaration(StringIdx, Box<IR>),
|
Declaration(StringIdx, Box<IR>),
|
||||||
TypeDefinition(TyIdx),
|
TypeDefinition(TyIdx),
|
||||||
TraitDefinition(TyIdx),
|
TraitDefinition(TyIdx),
|
||||||
|
ImplementTrait(TyIdx, TyIdx),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IR {
|
impl IR {
|
||||||
|
@ -82,6 +86,13 @@ impl IR {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_trait_implementation(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
IR::ImplementTrait(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A constant value.
|
/// A constant value.
|
||||||
|
|
|
@ -2,6 +2,11 @@ use crate::location::Location;
|
||||||
use crate::stable::StringIdx;
|
use crate::stable::StringIdx;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
/// The main "Type" struct.
|
||||||
|
/// Holds information about Huia Types and Traits.
|
||||||
|
///
|
||||||
|
/// FIXME:
|
||||||
|
/// Should probably support the Native option/result types.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Ty {
|
pub struct Ty {
|
||||||
name: Option<StringIdx>,
|
name: Option<StringIdx>,
|
||||||
|
|
Reference in a new issue