This commit is contained in:
James Harton 2019-03-17 18:52:21 +13:00
parent bd2177940c
commit 30fdff315b
13 changed files with 1029 additions and 493 deletions

View file

@ -1,5 +1,7 @@
{ {
"spellright.language": "en-NZ", "spellright.language": [
"en"
],
"spellright.documentTypes": [ "spellright.documentTypes": [
"markdown", "markdown",
"latex" "latex"

View file

@ -0,0 +1,25 @@
use crate::ir::IR;
#[derive(Debug, Default)]
pub struct Block {
ir: Vec<IR>,
}
impl Block {
pub fn push(&mut self, ir: IR) {
self.ir.push(ir);
}
pub fn pop(&mut self) -> Option<IR> {
self.ir.pop()
}
pub fn is_empty(&self) -> bool {
self.ir.is_empty()
}
/// Consumes the block and returns the IR data.
pub fn ir(self) -> Vec<IR> {
self.ir
}
}

View file

@ -2,17 +2,19 @@ use crate::error::CompileError;
use crate::function::{Clause, Function, FunctionIdx}; use crate::function::{Clause, Function, FunctionIdx};
use crate::ir::IR; use crate::ir::IR;
use crate::location::Location; use crate::location::Location;
use crate::method::{Method, MethodIdx};
use crate::stable::{StringIdx, StringTable}; use crate::stable::{StringIdx, StringTable};
use crate::ty::{Ty, TyIdx}; use crate::ty::{Ty, TyIdx};
use huia_parser::input_location::InputLocation; use huia_parser::input_location::InputLocation;
#[derive(Debug)] #[derive(Debug)]
pub struct Context { pub struct Context {
current_file: StringIdx,
errors: Vec<CompileError>, errors: Vec<CompileError>,
functions: Vec<Function>,
methods: Vec<Method>,
strings: StringTable, strings: StringTable,
types: Vec<Ty>, types: Vec<Ty>,
functions: Vec<Function>,
current_file: StringIdx,
} }
impl Context { impl Context {
@ -22,10 +24,12 @@ impl Context {
let errors = Vec::default(); let errors = Vec::default();
let functions = Vec::default(); let functions = Vec::default();
let types = Vec::default(); let types = Vec::default();
let methods = Vec::default();
Context { Context {
current_file, current_file,
errors, errors,
functions, functions,
methods,
strings, strings,
types, types,
} }
@ -106,6 +110,10 @@ impl Context {
self.types.get(usize::from(idx)) self.types.get(usize::from(idx))
} }
pub fn get_type_mut(&mut self, idx: &TyIdx) -> Option<&mut Ty> {
self.types.get_mut(usize::from(idx))
}
pub fn location(&self, location: &InputLocation) -> Location { pub fn location(&self, location: &InputLocation) -> Location {
let path = self.strings.get(self.current_file.clone()).unwrap(); let path = self.strings.get(self.current_file.clone()).unwrap();
Location::new(location.clone(), path) Location::new(location.clone(), path)
@ -117,6 +125,12 @@ impl Context {
idx.into() idx.into()
} }
pub fn define_method(&mut self, method: Method) -> MethodIdx {
let idx = self.methods.len();
self.methods.push(method);
idx.into()
}
pub fn get_function(&self, idx: FunctionIdx) -> Option<&Function> { pub fn get_function(&self, idx: FunctionIdx) -> Option<&Function> {
self.functions.get(usize::from(idx)) self.functions.get(usize::from(idx))
} }

View file

@ -16,8 +16,10 @@ impl Function {
} }
} }
pub fn push(&mut self, clause: Clause) { pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: Vec<IR>) -> ClauseIdx {
self.clauses.push(clause); let idx = self.clauses.len();
self.clauses.push(Clause::new(arguments, block));
idx.into()
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
@ -32,19 +34,12 @@ pub struct Clause {
} }
impl Clause { impl Clause {
pub fn new(arguments: Vec<(StringIdx, TyIdx)>) -> Clause { pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: Vec<IR>) -> Clause {
Clause { Clause { arguments, body }
arguments,
body: Vec::new(),
}
}
pub fn push(&mut self, ir: IR) {
self.body.push(ir);
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub struct FunctionIdx(usize); pub struct FunctionIdx(usize);
impl From<usize> for FunctionIdx { impl From<usize> for FunctionIdx {
@ -65,6 +60,27 @@ impl From<&FunctionIdx> for usize {
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub struct ClauseIdx(usize);
impl From<usize> for ClauseIdx {
fn from(i: usize) -> ClauseIdx {
ClauseIdx(i)
}
}
impl From<ClauseIdx> for usize {
fn from(i: ClauseIdx) -> usize {
i.0
}
}
impl From<&ClauseIdx> for usize {
fn from(i: &ClauseIdx) -> usize {
i.0
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -75,8 +91,7 @@ mod test {
let mut fun = Function::new(rt); let mut fun = Function::new(rt);
assert!(fun.is_empty()); assert!(fun.is_empty());
let clause = Clause::new(Vec::new()); fun.push(Vec::new(), Vec::new());
fun.push(clause);
assert!(!fun.is_empty()); assert!(!fun.is_empty());
} }

View file

@ -1,25 +1,20 @@
use crate::block::Block;
use crate::context::Context; use crate::context::Context;
use crate::function::{Clause, Function}; use crate::function::Function;
use crate::ir::{Val, IR}; use crate::ir::{Val, IR};
use crate::method::Method;
use crate::stable::StringIdx; use crate::stable::StringIdx;
use crate::ty::TyIdx; 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.
/// FIXME: /// FIXME:
/// Maybe push a named scope somehow when defining types so that we can figure /// Maybe push a named block somehow when defining types so that we can figure
/// out where we are when building methods, etc. /// out where we are when building methods, etc.
#[derive(Default, Debug)] #[derive(Debug)]
struct Builder { struct Builder {
/// The IR stack - used to compose intermediate values. blocks: Vec<Block>,
ir_stack: Vec<IR>, types: Vec<TyIdx>,
/// Type stack - used to track which type is currently being defined.
ty_stack: Vec<TyIdx>,
/// Function stack - used to track which function is currently being defined,
fn_stack: Vec<Function>,
clause_stack: Vec<Clause>,
} }
impl Builder { impl Builder {
@ -28,47 +23,6 @@ impl Builder {
/// Any IR will be on the Builder's stack. /// Any IR will be on the Builder's stack.
pub fn build(&mut self, node: Term, mut context: &mut Context) { pub fn build(&mut self, node: Term, mut context: &mut Context) {
match node.node_type() { match node.node_type() {
NodeType::Atom => {
let ty_idx = context.constant_string("Huia.Native.Atom");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let idx = context.constant_string(node.atom().unwrap().value_ref().as_str());
self.push_ir(IR::Constant(ty, Val::Atom(idx)));
}
NodeType::Boolean => {
let ty_idx = context.constant_string("Huia.Native.Boolean");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let value = *node.boolean().unwrap().value_ref();
self.push_ir(IR::Constant(ty, Val::Boolean(value)));
}
NodeType::Float => {
let ty_idx = context.constant_string("Huia.Native.Float");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let value = *node.float().unwrap().value_ref();
self.push_ir(IR::Constant(ty, Val::Float(value)));
}
NodeType::Integer => {
let ty_idx = context.constant_string("Huia.Native.Integer");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let value = *node.integer().unwrap().value_ref();
self.push_ir(IR::Constant(ty, Val::Integer(value)));
}
NodeType::String => {
let ty_idx = context.constant_string("Huia.Native.String");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let idx = context.constant_string(node.string().unwrap().value_ref().as_str());
self.push_ir(IR::Constant(ty, Val::String(idx)));
}
NodeType::Ty => {
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
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");
let location = context.location(&node.location()); let location = context.location(&node.location());
@ -85,24 +39,19 @@ impl Builder {
.collect(); .collect();
self.push_ir(IR::Constant(ty, Val::Array(elements))); self.push_ir(IR::Constant(ty, Val::Array(elements)));
} }
NodeType::Map => { NodeType::Atom => {
let ty_idx = context.constant_string("Huia.Native.Map"); let ty_idx = context.constant_string("Huia.Native.Atom");
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 elements = node self.push_ir(IR::Constant(ty, Val::Atom(idx)));
.map() }
.unwrap() NodeType::Boolean => {
.iter() let ty_idx = context.constant_string("Huia.Native.Boolean");
.map(|(key, value)| { let location = context.location(&node.location());
self.build(key.clone(), &mut context); let ty = context.reference_type(&ty_idx, location);
let key = self.pop_ir().unwrap(); let value = *node.boolean().unwrap().value_ref();
self.build(value.clone(), &mut context); self.push_ir(IR::Constant(ty, Val::Boolean(value)));
let value = self.pop_ir().unwrap();
(key, value)
})
.collect();
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();
@ -112,6 +61,19 @@ impl Builder {
let lhs = self.pop_ir().unwrap(); let lhs = self.pop_ir().unwrap();
self.push_ir(IR::Infix(op.value_ref().clone(), Box::new((lhs, rhs)))); self.push_ir(IR::Infix(op.value_ref().clone(), Box::new((lhs, rhs))));
} }
NodeType::Call => {
let (name, args) = node.call().unwrap();
let name = context.constant_string(name.value_ref().as_str());
self.push_block();
for node in args {
self.build(node.clone(), &mut context);
}
let arguments = self.pop_block().unwrap();
self.push_ir(IR::GetLocal(name));
self.push_ir(IR::Call(arguments.ir()));
}
NodeType::Constructor => { NodeType::Constructor => {
let (ty, props) = node.constructor().unwrap(); let (ty, props) = node.constructor().unwrap();
let ty_idx = context.constant_string(ty.value_ref().as_str()); let ty_idx = context.constant_string(ty.value_ref().as_str());
@ -123,120 +85,25 @@ 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.ir_stack.pop().unwrap(); let value = self.pop_ir().unwrap();
(key, value) (key, value)
}) })
.collect(); .collect();
self.push_ir(IR::Constructor(ty, elements)); self.push_ir(IR::Constructor(ty, elements));
} }
NodeType::Unary => { NodeType::Declaration => {
let (op, rhs) = node.unary().unwrap(); let (name, rhs) = node.declaration().unwrap();
let name = context.constant_string(name.value_ref().as_str());
self.build(rhs.clone(), &mut context); self.build(rhs.clone(), &mut context);
let rhs = self.pop_ir().unwrap(); let rhs = self.pop_ir().unwrap();
self.push_ir(IR::Unary(op.value_ref().clone(), Box::new(rhs))); self.push_ir(IR::SetLocal(name, Box::new(rhs)));
} }
NodeType::Call => { NodeType::Float => {
let (name, args) = node.call().unwrap(); let ty_idx = context.constant_string("Huia.Native.Float");
let name = context.constant_string(name.value_ref().as_str());
let elements = args
.iter()
.map(|node| {
self.build(node.clone(), &mut context);
self.pop_ir().unwrap()
})
.collect();
self.push_ir(IR::Call(name, elements));
}
NodeType::Declaration => {
let (name, node) = node.declaration().unwrap();
let name = context.constant_string(name.value_ref().as_str());
self.build(node.clone(), &mut context);
let node = self.pop_ir().unwrap();
self.push_ir(IR::Declaration(name, Box::new(node)));
}
NodeType::TypeDef => {
let (ty, properties, body) = node.typedef().unwrap();
let ty_idx = context.constant_string(ty.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 properties = properties let value = *node.float().unwrap().value_ref();
.iter() self.push_ir(IR::Constant(ty, Val::Float(value)));
.map(|(key, value)| {
let key = context.constant_string(key.value_ref().as_str());
let location = context.location(&value.location());
let types = value
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect();
let ty = context.anonymous_trait(types, location);
(key, ty)
})
.collect();
let ty = context.declare_type(&ty_idx, properties, location);
self.push_ty(ty.clone());
for node in body {
self.build(node.clone(), &mut context);
}
self.pop_ty();
}
NodeType::TraitDef => {
let (ty, typespec, body) = node.traitdef().unwrap();
let ty_idx = context.constant_string(ty.value_ref().as_str());
let location = context.location(&node.location());
let types = if typespec.is_some() {
typespec
.unwrap()
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect()
} else {
Vec::new()
};
let ty = context.declare_trait(&ty_idx, types, location);
self.push_ty(ty.clone());
for node in body {
self.build(node.clone(), &mut context);
}
self.pop_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 tr = context.reference_type(&ty_idx, location.clone());
// the parser state should stop us from being in an
// implementation whilst not inside a type definition.
let ty = self.peek_ty().unwrap().clone();
let im = context.declare_impl(tr, ty, location);
self.push_ty(im.clone());
for node in body {
self.build(node.clone(), &mut context);
}
self.pop_ty();
} }
NodeType::Function => { NodeType::Function => {
let function = node.function().unwrap(); let function = node.function().unwrap();
@ -265,72 +132,407 @@ impl Builder {
}) })
.collect(); .collect();
// FIXME: We need to put the built nodes into a scope self.push_block();
// pointing at the current clause rather than just stuffing
// them into the stack where they're just sitting there
// doing no good to anyone.
self.push_clause(Clause::new(arguments));
for node in clause.body() { for node in clause.body() {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
fun.push(self.pop_clause().unwrap()); let clause_data = self.pop_block().unwrap().ir();
fun.push(arguments, clause_data);
} }
let idx = context.define_function(fun); let fun_idx = context.define_function(fun);
self.push_ir(IR::Function(idx)); self.push_ir(IR::Function(fun_idx));
} }
// NodeType::PublicMethod => { NodeType::If => {
// let (name, args, typespec, body) = node.public_method().unwrap(); let (test, positive, negative) = node.if_expr().unwrap();
let location = context.location(&node.location());
// let name = context.constant_string(name.value_ref().as_str()); self.build(test.clone(), &mut context);
// let location = context.location(&node.location()); let test = self.pop_ir().unwrap();
// } let result_type = context.unknown_type(location);
_ => (),
self.push_block();
for node in positive {
self.build(node.clone(), &mut context);
}
let positive = self.pop_block().unwrap().ir();
self.push_block();
for node in negative {
self.build(node.clone(), &mut context);
}
let negative = self.pop_block().unwrap().ir();
self.push_ir(IR::If(Box::new(test), positive, negative, result_type));
}
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 tr = context.reference_type(&ty_idx, location.clone());
// the parser state should stop us from being in an
// implementation whilst not inside a type definition.
let ty = self.peek_ty().unwrap().clone();
let im = context.declare_impl(tr, ty, location);
self.push_ty(im.clone());
self.push_block();
for node in body {
self.build(node.clone(), &mut context);
}
self.pop_block();
self.pop_ty();
}
NodeType::Integer => {
let ty_idx = context.constant_string("Huia.Native.Integer");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let value = *node.integer().unwrap().value_ref();
self.push_ir(IR::Constant(ty, Val::Integer(value)));
}
NodeType::Local => {
let name = node.local().unwrap();
let name = context.constant_string(name.value_ref().as_str());
self.push_ir(IR::GetLocal(name));
}
NodeType::Map => {
let ty_idx = context.constant_string("Huia.Native.Map");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let elements = node
.map()
.unwrap()
.iter()
.map(|(key, value)| {
self.build(key.clone(), &mut context);
let key = self.pop_ir().unwrap();
self.build(value.clone(), &mut context);
let value = self.pop_ir().unwrap();
(key, value)
})
.collect();
self.push_ir(IR::Constant(ty, Val::Map(elements)));
}
NodeType::PropertyGet => {
let ident =
context.constant_string(node.property_get().unwrap().value_ref().as_str());
self.push_ir(IR::GetProperty(ident));
}
NodeType::PropertySet => {
let elements: Vec<(StringIdx, IR)> = node
.property_set()
.unwrap()
.iter()
.map(|(key, value)| {
let key = context.constant_string(key.value_ref().as_str());
self.build(value.clone(), &mut context);
let value = self.pop_ir().unwrap();
(key, value)
})
.collect();
self.push_ir(IR::SetProperties(elements))
}
NodeType::PrivateMethod => {
let current_ty = self.peek_ty().unwrap();
let location = context.location(&node.location());
let (ident, args, return_type, block) = node.private_method().unwrap();
let method_name = context.constant_string(ident.value_ref().as_str());
let return_type = match return_type {
Some(rt) => {
let types = rt
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location.clone())
})
.collect();
context.anonymous_trait(types, location.clone())
}
None => context.unknown_type(location.clone()),
};
let mut method = Method::new_private(method_name, return_type, current_ty.clone());
let arguments: Vec<(StringIdx, TyIdx)> = args
.iter()
.map(|(name, type_spec)| {
let name = context.constant_string(name.value_ref().as_str());
let location = context.location(&type_spec.location());
let types = type_spec
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect();
let ty = context.anonymous_trait(types, location);
(name, ty)
})
.collect();
self.push_block();
for node in block {
self.build(node.clone(), &mut context);
}
let clause_data = self.pop_block().unwrap().ir();
method.push(arguments, clause_data);
context.define_method(method);
}
NodeType::PublicMethod => {
let current_ty = self.peek_ty().unwrap();
let location = context.location(&node.location());
let (ident, args, return_type, block) = node.public_method().unwrap();
let method_name = context.constant_string(ident.value_ref().as_str());
let return_type = match return_type {
Some(rt) => {
let types = rt
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location.clone())
})
.collect();
context.anonymous_trait(types, location.clone())
}
None => context.unknown_type(location.clone()),
};
let mut method = Method::new_public(method_name, return_type, current_ty.clone());
let arguments: Vec<(StringIdx, TyIdx)> = args
.iter()
.map(|(name, type_spec)| {
let name = context.constant_string(name.value_ref().as_str());
let location = context.location(&type_spec.location());
let types = type_spec
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect();
let ty = context.anonymous_trait(types, location);
(name, ty)
})
.collect();
self.push_block();
for node in block {
self.build(node.clone(), &mut context);
}
let clause_data = self.pop_block().unwrap().ir();
method.push(arguments, clause_data);
context.define_method(method);
}
NodeType::StaticMethod => {
let current_ty = self.peek_ty().unwrap();
let location = context.location(&node.location());
let (ident, args, return_type, block) = node.static_method().unwrap();
let method_name = context.constant_string(ident.value_ref().as_str());
let return_type = match return_type {
Some(rt) => {
let types = rt
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location.clone())
})
.collect();
context.anonymous_trait(types, location.clone())
}
None => context.unknown_type(location.clone()),
};
let mut method = Method::new_static(method_name, return_type, current_ty.clone());
let arguments: Vec<(StringIdx, TyIdx)> = args
.iter()
.map(|(name, type_spec)| {
let name = context.constant_string(name.value_ref().as_str());
let location = context.location(&type_spec.location());
let types = type_spec
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect();
let ty = context.anonymous_trait(types, location);
(name, ty)
})
.collect();
self.push_block();
for node in block {
self.build(node.clone(), &mut context);
}
let clause_data = self.pop_block().unwrap().ir();
method.push(arguments, clause_data);
context.define_method(method);
}
NodeType::String => {
let ty_idx = context.constant_string("Huia.Native.String");
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
let idx = context.constant_string(node.string().unwrap().value_ref().as_str());
self.push_ir(IR::Constant(ty, Val::String(idx)));
}
NodeType::TraitDef => {
let (ty, typespec, body) = node.traitdef().unwrap();
let ty_idx = context.constant_string(ty.value_ref().as_str());
let location = context.location(&node.location());
let types = if typespec.is_some() {
typespec
.unwrap()
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect()
} else {
Vec::new()
};
let ty = context.declare_trait(&ty_idx, types, location);
self.push_ty(ty.clone());
for node in body {
self.build(node.clone(), &mut context);
}
self.pop_block();
self.pop_ty();
}
NodeType::Ty => {
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
let location = context.location(&node.location());
let ty = context.reference_type(&ty_idx, location);
self.push_ir(IR::TypeReference(ty));
}
NodeType::TypeDef => {
let (ty, properties, body) = node.typedef().unwrap();
let ty_idx = context.constant_string(ty.value_ref().as_str());
let location = context.location(&node.location());
let properties = properties
.iter()
.map(|(key, value)| {
let key = context.constant_string(key.value_ref().as_str());
let location = context.location(&value.location());
let types = value
.value_ref()
.iter()
.map(|node| {
let name = context.constant_string(node.value_ref().as_str());
let location = context.location(&node.location());
context.reference_type(&name, location)
})
.collect();
let ty = context.anonymous_trait(types, location);
(key, ty)
})
.collect();
let ty = context.declare_type(&ty_idx, properties, location);
self.push_ty(ty.clone());
self.push_block();
for node in body {
self.build(node.clone(), &mut context);
}
let block = self.pop_block().unwrap();
assert!(block.is_empty());
self.pop_ty();
}
NodeType::Unary => {
let (op, rhs) = node.unary().unwrap();
self.build(rhs.clone(), &mut context);
let rhs = self.pop_ir().unwrap();
self.push_ir(IR::Unary(op.value_ref().clone(), Box::new(rhs)));
}
_ => unreachable!("Unexpected node type: {:?}", node.node_type()),
} }
} }
pub fn push_ir(&mut self, ir: IR) { fn push_block(&mut self) {
self.ir_stack.push(ir); self.blocks.push(Block::default());
}
fn pop_block(&mut self) -> Option<Block> {
self.blocks.pop()
}
fn peek_block(&self) -> Option<&Block> {
let len = self.blocks.len();
self.blocks.get(len - 1)
}
fn peek_block_mut(&mut self) -> Option<&mut Block> {
let len = self.blocks.len();
self.blocks.get_mut(len - 1)
}
fn push_ir(&mut self, ir: IR) {
self.peek_block_mut().unwrap().push(ir);
} }
pub fn pop_ir(&mut self) -> Option<IR> { pub fn pop_ir(&mut self) -> Option<IR> {
self.ir_stack.pop() self.peek_block_mut().unwrap().pop()
} }
pub fn push_ty(&mut self, ty: TyIdx) { fn push_ty(&mut self, idx: TyIdx) {
self.ty_stack.push(ty); self.types.push(idx);
} }
pub fn pop_ty(&mut self) -> Option<TyIdx> { fn pop_ty(&mut self) -> Option<TyIdx> {
self.ty_stack.pop() self.types.pop()
} }
pub fn peek_ty(&self) -> Option<&TyIdx> { fn peek_ty(&mut self) -> Option<&TyIdx> {
let len = self.ty_stack.len(); let len = self.types.len();
self.ty_stack.get(len - 1) self.types.get(len - 1)
} }
}
pub fn push_fn(&mut self, fun: Function) { impl Default for Builder {
self.fn_stack.push(fun); fn default() -> Builder {
} let blocks = vec![Block::default()];
let types = Vec::default();
pub fn pop_fn(&mut self) -> Option<Function> { Builder { blocks, types }
self.fn_stack.pop()
}
pub fn push_clause(&mut self, clause: Clause) {
self.clause_stack.push(clause);
}
pub fn peek_clause_mut(&mut self) -> Option<&mut Clause> {
let len = self.clause_stack.len();
self.clause_stack.get_mut(len - 1)
}
pub fn pop_clause(&mut self) -> Option<Clause> {
self.clause_stack.pop()
} }
} }
@ -458,19 +660,21 @@ mod test {
let mut builder = Builder::default(); let mut builder = Builder::default();
let mut context = Context::test(); let mut context = Context::test();
builder.build(term, &mut context); builder.build(term, &mut context);
let ir = builder.pop_ir().unwrap(); let call = builder.pop_ir().unwrap();
assert!(ir.is_call()); let receiver = builder.pop_ir().unwrap();
assert!(call.is_call());
assert!(receiver.is_get_local());
assert!(context.find_type("Huia.Native.Integer").is_some()); assert!(context.find_type("Huia.Native.Integer").is_some());
} }
#[test] #[test]
fn test_declaration() { fn test_set_local() {
let term = Term::input(r#" let x = 123 "#).unwrap()[0].clone(); let term = Term::input(r#" let x = 123 "#).unwrap()[0].clone();
let mut builder = Builder::default(); let mut builder = Builder::default();
let mut context = Context::test(); let mut context = Context::test();
builder.build(term, &mut context); builder.build(term, &mut context);
let ir = builder.pop_ir().unwrap(); let ir = builder.pop_ir().unwrap();
assert!(ir.is_declaration()); assert!(ir.is_set_local());
assert!(context.find_type("Huia.Native.Integer").is_some()); assert!(context.find_type("Huia.Native.Integer").is_some());
} }
@ -525,4 +729,46 @@ mod test {
.unwrap(); .unwrap();
assert!(!fun.is_empty()); assert!(!fun.is_empty());
} }
#[test]
fn test_acceptance() {
let term = Term::file(
r#"
type Delorean(speed: Integer, year: Integer, target_year: Integer) do
defs init() do
Delorean { speed: 0, year: 1985, target_year: 1985 }
end
def current_speed() do
@speed
end
def accelerate() do
let speed = @speed + 1
if (speed == 88) do
@{ speed: speed, year: @target_year }
else
@{ speed: speed }
end
end
impl TimeMachine do
def current_year() do
@year
end
def set_target_year(year: Integer) do
@{ target_year: year }
end
end
end
"#,
)
.unwrap()[0]
.clone();
let mut builder = Builder::default();
let mut context = Context::test();
builder.build(term, &mut context);
}
} }

View file

@ -10,19 +10,49 @@ use huia_parser::ast::unary::Operator as UnOp;
/// ///
/// FIXME: /// FIXME:
/// IR should have a location too if possible. /// IR should have a location too if possible.
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum IR { pub enum IR {
/// Call top of the stack with arguments.
Call(Vec<IR>),
/// A constant value of the specified type.
Constant(TyIdx, Val), Constant(TyIdx, Val),
TypeReference(TyIdx), /// Construct an instance of type with the provided properties.
Infix(BinOp, Box<(IR, IR)>),
Constructor(TyIdx, Vec<(StringIdx, IR)>), Constructor(TyIdx, Vec<(StringIdx, IR)>),
Unary(UnOp, Box<IR>), /// Reference an anonymous function from the context.
Call(StringIdx, Vec<IR>),
Declaration(StringIdx, Box<IR>),
Function(FunctionIdx), Function(FunctionIdx),
/// Reference a local variable.
GetLocal(StringIdx),
/// Refernce an instance property.
GetProperty(StringIdx),
/// Consists of test, positives, negatives and a return type.
If(Box<IR>, Vec<IR>, Vec<IR>, TyIdx),
/// A binary operation with LHS and RHS.
Infix(BinOp, Box<(IR, IR)>),
/// Take a value and set it as a local variable.
SetLocal(StringIdx, Box<IR>),
/// Set properties on an instance, returning the modified instance.
SetProperties(Vec<(StringIdx, IR)>),
/// A direct type reference.
TypeReference(TyIdx),
/// A unary operation on a value.
Unary(UnOp, Box<IR>),
} }
impl IR { impl IR {
pub fn function(&self) -> Option<&FunctionIdx> {
match self {
IR::Function(ref idx) => Some(idx),
_ => None,
}
}
pub fn is_call(&self) -> bool {
match self {
IR::Call(..) => true,
_ => false,
}
}
pub fn is_constant(&self) -> bool { pub fn is_constant(&self) -> bool {
match self { match self {
IR::Constant(..) => true, IR::Constant(..) => true,
@ -30,20 +60,6 @@ impl IR {
} }
} }
pub fn is_type_reference(&self) -> bool {
match self {
IR::TypeReference(..) => true,
_ => false,
}
}
pub fn is_infix(&self) -> bool {
match self {
IR::Infix(..) => true,
_ => false,
}
}
pub fn is_constuctor(&self) -> bool { pub fn is_constuctor(&self) -> bool {
match self { match self {
IR::Constructor(..) => true, IR::Constructor(..) => true,
@ -51,27 +67,6 @@ impl IR {
} }
} }
pub fn is_unary(&self) -> bool {
match self {
IR::Unary(..) => true,
_ => false,
}
}
pub fn is_call(&self) -> bool {
match self {
IR::Call(..) => true,
_ => false,
}
}
pub fn is_declaration(&self) -> bool {
match self {
IR::Declaration(..) => true,
_ => false,
}
}
pub fn is_function(&self) -> bool { pub fn is_function(&self) -> bool {
match self { match self {
IR::Function(..) => true, IR::Function(..) => true,
@ -79,16 +74,51 @@ impl IR {
} }
} }
pub fn function(&self) -> Option<&FunctionIdx> { pub fn is_get_local(&self) -> bool {
match self { match self {
IR::Function(ref idx) => Some(idx), IR::GetLocal(..) => true,
_ => None, _ => false,
}
}
pub fn is_get_property(&self) -> bool {
match self {
IR::GetProperty(..) => true,
_ => false,
}
}
pub fn is_infix(&self) -> bool {
match self {
IR::Infix(..) => true,
_ => false,
}
}
pub fn is_type_reference(&self) -> bool {
match self {
IR::TypeReference(..) => true,
_ => false,
}
}
pub fn is_set_local(&self) -> bool {
match self {
IR::SetLocal(..) => true,
_ => false,
}
}
pub fn is_unary(&self) -> bool {
match self {
IR::Unary(..) => true,
_ => false,
} }
} }
} }
/// A constant value. /// A constant value.
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum Val { pub enum Val {
Atom(StringIdx), Atom(StringIdx),
Boolean(bool), Boolean(bool),

View file

@ -1,7 +1,9 @@
mod block;
mod context; mod context;
mod error; mod error;
mod function; mod function;
mod ir; mod ir;
mod location; mod location;
mod method;
mod stable; mod stable;
mod ty; mod ty;

103
huia-compiler/src/method.rs Normal file
View file

@ -0,0 +1,103 @@
use crate::function::{Clause, ClauseIdx};
use crate::ir::IR;
use crate::stable::StringIdx;
use crate::ty::TyIdx;
#[derive(Debug)]
pub struct Method {
clauses: Vec<Clause>,
name: StringIdx,
return_type: TyIdx,
kind: MethodKind,
upon: TyIdx,
}
impl Method {
pub fn new_public(name: StringIdx, return_type: TyIdx, upon: TyIdx) -> Method {
Method {
clauses: Vec::default(),
name,
return_type,
kind: MethodKind::Public,
upon,
}
}
pub fn new_private(name: StringIdx, return_type: TyIdx, upon: TyIdx) -> Method {
Method {
clauses: Vec::default(),
name,
return_type,
kind: MethodKind::Private,
upon,
}
}
pub fn new_static(name: StringIdx, return_type: TyIdx, upon: TyIdx) -> Method {
Method {
clauses: Vec::default(),
name,
return_type,
kind: MethodKind::Static,
upon,
}
}
pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: Vec<IR>) -> ClauseIdx {
let idx = self.clauses.len();
self.clauses.push(Clause::new(arguments, block));
idx.into()
}
pub fn is_empty(&self) -> bool {
self.clauses.is_empty()
}
pub fn is_public(&self) -> bool {
match self.kind {
MethodKind::Public => true,
_ => false,
}
}
pub fn is_private(&self) -> bool {
match self.kind {
MethodKind::Private => true,
_ => false,
}
}
pub fn is_static(&self) -> bool {
match self.kind {
MethodKind::Static => true,
_ => false,
}
}
}
#[derive(Debug)]
enum MethodKind {
Public,
Private,
Static,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MethodIdx(usize);
impl From<usize> for MethodIdx {
fn from(i: usize) -> MethodIdx {
MethodIdx(i)
}
}
impl From<MethodIdx> for usize {
fn from(i: MethodIdx) -> usize {
i.0
}
}
impl From<&MethodIdx> for usize {
fn from(i: &MethodIdx) -> usize {
i.0
}
}

View file

@ -1,3 +1,4 @@
use crate::ir::IR;
use crate::location::Location; use crate::location::Location;
use crate::stable::StringIdx; use crate::stable::StringIdx;
use std::fmt; use std::fmt;
@ -13,6 +14,7 @@ pub struct Ty {
location: Location, location: Location,
kind: TyKind, kind: TyKind,
inner: TyInner, inner: TyInner,
body: Vec<IR>,
} }
impl Ty { impl Ty {
@ -26,6 +28,7 @@ impl Ty {
location, location,
kind: TyKind::Type, kind: TyKind::Type,
inner: TyInner::Type { properties }, inner: TyInner::Type { properties },
body: Vec::default(),
} }
} }
@ -35,6 +38,7 @@ impl Ty {
location, location,
kind: TyKind::Trait, kind: TyKind::Trait,
inner: TyInner::Trait { dependencies }, inner: TyInner::Trait { dependencies },
body: Vec::default(),
} }
} }
@ -44,6 +48,7 @@ impl Ty {
location, location,
kind: TyKind::Unresolved, kind: TyKind::Unresolved,
inner: TyInner::Empty, inner: TyInner::Empty,
body: Vec::default(),
} }
} }
@ -53,6 +58,7 @@ impl Ty {
location, location,
kind: TyKind::Impl, kind: TyKind::Impl,
inner: TyInner::Impl { ty, tr }, inner: TyInner::Impl { ty, tr },
body: Vec::default(),
} }
} }
@ -62,6 +68,7 @@ impl Ty {
location, location,
kind: TyKind::Unresolved, kind: TyKind::Unresolved,
inner: TyInner::Empty, inner: TyInner::Empty,
body: Vec::default(),
} }
} }

View file

@ -52,6 +52,15 @@ impl<'a> From<Pair<'a, Rule>> for Identifier {
location: InputLocation::from(pair.into_span()), location: InputLocation::from(pair.into_span()),
} }
} }
Rule::property_get => {
let value = pair.clone().into_span().as_str();
let len = value.len();
let value = value.get(1..len).unwrap().to_string();
Identifier {
value,
location: InputLocation::from(pair.into_span()),
}
}
_ => unreachable!( _ => unreachable!(
"Expected pair to be an Identifier (received {:?})", "Expected pair to be an Identifier (received {:?})",
pair.as_rule() pair.as_rule()

View file

@ -37,8 +37,11 @@ pub enum NodeType {
Call, Call,
Declaration, Declaration,
Local,
Function, Function,
If,
Local,
PropertyGet,
PropertySet,
TypeDef, TypeDef,
TraitDef, TraitDef,
@ -59,6 +62,7 @@ enum Inner {
Declaration(Identifier, Box<Term>), Declaration(Identifier, Box<Term>),
Float(Float), Float(Float),
Function(Function), Function(Function),
If(Box<Term>, Vec<Term>, Vec<Term>),
ImplDef(Ty, Vec<Term>), ImplDef(Ty, Vec<Term>),
Integer(Integer), Integer(Integer),
Local(Local), Local(Local),
@ -69,6 +73,8 @@ enum Inner {
Option<TypeSpec>, Option<TypeSpec>,
Vec<Term>, Vec<Term>,
), ),
PropertyGet(Identifier),
PropertySet(Vec<(Identifier, Term)>),
PublicMethod( PublicMethod(
Identifier, Identifier,
Vec<(Identifier, TypeSpec)>, Vec<(Identifier, TypeSpec)>,
@ -136,9 +142,12 @@ impl Term {
Inner::Declaration(..) => NodeType::Declaration, Inner::Declaration(..) => NodeType::Declaration,
Inner::Function(..) => NodeType::Function, Inner::Function(..) => NodeType::Function,
Inner::Float(..) => NodeType::Float, Inner::Float(..) => NodeType::Float,
Inner::If(..) => NodeType::If,
Inner::Integer(..) => NodeType::Integer, Inner::Integer(..) => NodeType::Integer,
Inner::Local(..) => NodeType::Local, Inner::Local(..) => NodeType::Local,
Inner::Map(..) => NodeType::Map, Inner::Map(..) => NodeType::Map,
Inner::PropertyGet(..) => NodeType::PropertyGet,
Inner::PropertySet(..) => NodeType::PropertySet,
Inner::String(..) => NodeType::String, Inner::String(..) => NodeType::String,
Inner::Unary(..) => NodeType::Unary, Inner::Unary(..) => NodeType::Unary,
Inner::TypeDef(..) => NodeType::TypeDef, Inner::TypeDef(..) => NodeType::TypeDef,
@ -185,13 +194,6 @@ impl Term {
} }
} }
pub fn ty(&self) -> Option<&Ty> {
match self.inner {
Inner::Ty(ref node) => Some(node),
_ => None,
}
}
pub fn constructor(&self) -> Option<(&Ty, &Vec<(Identifier, Term)>)> { pub fn constructor(&self) -> Option<(&Ty, &Vec<(Identifier, Term)>)> {
match self.inner { match self.inner {
Inner::Constructor(ref ty, ref properties) => Some((ty, properties)), Inner::Constructor(ref ty, ref properties) => Some((ty, properties)),
@ -199,82 +201,6 @@ impl Term {
} }
} }
pub fn traitdef(&self) -> Option<(&Ty, Option<&TypeSpec>, &Vec<Term>)> {
match self.inner {
Inner::TraitDef(ref ty, ref reqs, ref body) => Some((ty, reqs.as_ref(), body)),
_ => None,
}
}
pub fn typedef(&self) -> Option<(&Ty, &Vec<(Identifier, TypeSpec)>, &Vec<Term>)> {
match self.inner {
Inner::TypeDef(ref ty, ref props, ref body) => Some((ty, props, body)),
_ => None,
}
}
pub fn impldef(&self) -> Option<(&Ty, &Vec<Term>)> {
match self.inner {
Inner::ImplDef(ref ty, ref body) => Some((ty, body)),
_ => None,
}
}
pub fn function(&self) -> Option<&Function> {
match self.inner {
Inner::Function(ref function) => Some(function),
_ => None,
}
}
pub fn public_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::PublicMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn private_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::PrivateMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn static_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::StaticMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn declaration(&self) -> Option<(&Identifier, &Term)> { pub fn declaration(&self) -> Option<(&Identifier, &Term)> {
match self.inner { match self.inner {
Inner::Declaration(ref name, ref value) => Some((name, value)), Inner::Declaration(ref name, ref value) => Some((name, value)),
@ -289,6 +215,27 @@ impl Term {
} }
} }
pub fn function(&self) -> Option<&Function> {
match self.inner {
Inner::Function(ref function) => Some(function),
_ => None,
}
}
pub fn if_expr(&self) -> Option<(&Term, &Vec<Term>, &Vec<Term>)> {
match self.inner {
Inner::If(ref test, ref positives, ref negatives) => Some((test, positives, negatives)),
_ => None,
}
}
pub fn impldef(&self) -> Option<(&Ty, &Vec<Term>)> {
match self.inner {
Inner::ImplDef(ref ty, ref body) => Some((ty, body)),
_ => None,
}
}
pub fn integer(&self) -> Option<&Integer> { pub fn integer(&self) -> Option<&Integer> {
match self.inner { match self.inner {
Inner::Integer(ref node) => Some(node), Inner::Integer(ref node) => Some(node),
@ -310,6 +257,68 @@ impl Term {
} }
} }
pub fn private_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::PrivateMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn property_get(&self) -> Option<&Identifier> {
match self.inner {
Inner::PropertyGet(ref name) => Some(name),
_ => None,
}
}
pub fn property_set(&self) -> Option<&Vec<(Identifier, Term)>> {
match self.inner {
Inner::PropertySet(ref values) => Some(values),
_ => None,
}
}
pub fn public_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::PublicMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn static_method(
&self,
) -> Option<(
&Identifier,
&Vec<(Identifier, TypeSpec)>,
Option<&TypeSpec>,
&Vec<Term>,
)> {
match self.inner {
Inner::StaticMethod(ref name, ref args, ref rval, ref body) => {
Some((name, args, rval.as_ref(), body))
}
_ => None,
}
}
pub fn string(&self) -> Option<&String> { pub fn string(&self) -> Option<&String> {
match self.inner { match self.inner {
Inner::String(ref node) => Some(node), Inner::String(ref node) => Some(node),
@ -317,6 +326,27 @@ impl Term {
} }
} }
pub fn traitdef(&self) -> Option<(&Ty, Option<&TypeSpec>, &Vec<Term>)> {
match self.inner {
Inner::TraitDef(ref ty, ref reqs, ref body) => Some((ty, reqs.as_ref(), body)),
_ => None,
}
}
pub fn ty(&self) -> Option<&Ty> {
match self.inner {
Inner::Ty(ref node) => Some(node),
_ => None,
}
}
pub fn typedef(&self) -> Option<(&Ty, &Vec<(Identifier, TypeSpec)>, &Vec<Term>)> {
match self.inner {
Inner::TypeDef(ref ty, ref props, ref body) => Some((ty, props, body)),
_ => None,
}
}
pub fn unary(&self) -> Option<(&Unary, &Term)> { pub fn unary(&self) -> Option<(&Unary, &Term)> {
match self.inner { match self.inner {
Inner::Unary(ref op, ref rhs) => Some((op, rhs)), Inner::Unary(ref op, ref rhs) => Some((op, rhs)),
@ -408,6 +438,78 @@ impl<'a> From<Pair<'a, Rule>> for Term {
inner: Inner::Declaration(identifier, Box::new(value)), inner: Inner::Declaration(identifier, Box::new(value)),
} }
} }
Rule::defprivate => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::PrivateMethod(name, args, rval, block),
}
}
Rule::defpublic => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::PublicMethod(name, args, rval, block),
}
}
Rule::defstatic => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::StaticMethod(name, args, rval, block),
}
}
Rule::float => Term { Rule::float => Term {
location: InputLocation::from(pair.clone()), location: InputLocation::from(pair.clone()),
inner: Inner::Float(Float::from(pair)), inner: Inner::Float(Float::from(pair)),
@ -416,6 +518,38 @@ impl<'a> From<Pair<'a, Rule>> for Term {
location: InputLocation::from(pair.clone()), location: InputLocation::from(pair.clone()),
inner: Inner::Function(Function::from(pair)), inner: Inner::Function(Function::from(pair)),
}, },
Rule::if_expression => {
let mut inner = pair.clone().into_inner();
let test = Term::from(inner.next().unwrap());
let positives = inner
.next()
.unwrap()
.into_inner()
.map(|p| Term::from(p))
.collect();
let negatives = inner.next();
if negatives.is_some() {
let negatives = negatives.unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::If(Box::new(test), positives, negatives),
}
} else {
Term {
location: InputLocation::from(pair),
inner: Inner::If(Box::new(test), positives, Vec::default()),
}
}
}
Rule::impldef => {
let mut inner = pair.clone().into_inner();
let ty = Ty::from(inner.next().unwrap());
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::ImplDef(ty, block),
}
}
Rule::infix => precedence::climb(pair), Rule::infix => precedence::climb(pair),
Rule::integer => Term { Rule::integer => Term {
location: InputLocation::from(pair.clone()), location: InputLocation::from(pair.clone()),
@ -447,6 +581,26 @@ impl<'a> From<Pair<'a, Rule>> for Term {
inner: Inner::Map(contents), inner: Inner::Map(contents),
} }
} }
Rule::property_get => Term {
location: InputLocation::from(pair.clone()),
inner: Inner::PropertyGet(Identifier::from(pair)),
},
Rule::property_set => {
let values = pair
.clone()
.into_inner()
.map(|pair| {
let mut inner = pair.into_inner();
let name = Identifier::from(inner.next().unwrap());
let value = Term::from(inner.next().unwrap());
(name, value)
})
.collect();
Term {
location: InputLocation::from(pair),
inner: Inner::PropertySet(values),
}
}
Rule::string => Term { Rule::string => Term {
location: InputLocation::from(pair.clone()), location: InputLocation::from(pair.clone()),
inner: Inner::String(String::from(pair)), inner: Inner::String(String::from(pair)),
@ -460,7 +614,6 @@ impl<'a> From<Pair<'a, Rule>> for Term {
inner: Inner::Unary(operator, Box::new(rhs)), inner: Inner::Unary(operator, Box::new(rhs)),
} }
} }
Rule::traitdef => { Rule::traitdef => {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
let ty = Ty::from(inner.next().unwrap()); let ty = Ty::from(inner.next().unwrap());
@ -474,7 +627,6 @@ impl<'a> From<Pair<'a, Rule>> for Term {
inner: Inner::TraitDef(ty, reqs, block), inner: Inner::TraitDef(ty, reqs, block),
} }
} }
Rule::typedef => { Rule::typedef => {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
let ty = Ty::from(inner.next().unwrap()); let ty = Ty::from(inner.next().unwrap());
@ -496,89 +648,6 @@ impl<'a> From<Pair<'a, Rule>> for Term {
} }
} }
Rule::impldef => {
let mut inner = pair.clone().into_inner();
let ty = Ty::from(inner.next().unwrap());
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::ImplDef(ty, block),
}
}
Rule::defpublic => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::PublicMethod(name, args, rval, block),
}
}
Rule::defprivate => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::PrivateMethod(name, args, rval, block),
}
}
Rule::defstatic => {
let mut inner = pair.clone().into_inner();
let name = Identifier::from(inner.next().unwrap());
let args = inner
.next()
.unwrap()
.into_inner()
.map(|p| {
let mut inner = p.into_inner();
let keyword = Identifier::from(inner.next().unwrap());
let typespec = TypeSpec::from(inner.next().unwrap());
(keyword, typespec)
})
.collect();
let rval = match inner.next().unwrap().into_inner().next() {
Some(value) => Some(TypeSpec::from(value)),
_ => None,
};
let block = inner.next().unwrap().into_inner().map(Term::from).collect();
Term {
location: InputLocation::from(pair),
inner: Inner::StaticMethod(name, args, rval, block),
}
}
_ => panic!("Unexpected pair {:?}", pair), _ => panic!("Unexpected pair {:?}", pair),
} }
} }

View file

@ -23,11 +23,15 @@ impl<'a> From<pest::error::Error<Rule>> for ParseError {
pest::error::ErrorVariant::ParsingError { pest::error::ErrorVariant::ParsingError {
ref positives, ref positives,
ref negatives, ref negatives,
} => ParseError::PestError { } => {
// FIXME: Remove when we have real error formatting.
println!("Pest Error: {}", pest);
ParseError::PestError {
positives: positives.clone(), positives: positives.clone(),
negatives: negatives.clone(), negatives: negatives.clone(),
location: InputLocation::from(pest.location), location: InputLocation::from(pest.location),
}, }
}
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -7,10 +7,11 @@ reserved = { "end" | "let" | "true" | "false" }
expression = _{ infix | expression_inner } expression = _{ infix | expression_inner }
infix = { expression_inner ~ (binary_operator ~ expression_inner)+ } infix = { expression_inner ~ (binary_operator ~ expression_inner)+ }
expression_inner = _{ function | call | declaration | unary | literal | local | braced_expression } expression_inner = _{ if_expression | function | call | declaration | unary | literal | local | braced_expression }
braced_expression = _{ "(" ~ expression ~ ")" } braced_expression = _{ "(" ~ expression ~ ")" }
instance_espression = _{ property_get | property_set | expression }
declaration = { "let" ~ ident ~ assign ~ expression } declaration = { "let" ~ ident ~ assign ~ instance_espression }
unary = { unary_operator ~ (literal | local | braced_expression) } unary = { unary_operator ~ (literal | local | braced_expression) }
@ -37,12 +38,13 @@ impldefblock = { ("do" ~ methoddef* ~ "end")? }
methoddef = _{ defpublic | defprivate | defstatic } methoddef = _{ defpublic | defprivate | defstatic }
methodargs = { defargs? } methodargs = { defargs? }
methodname = @{ ident ~ ("?")? } methodname = @{ ident ~ ("?")? }
methodblock = { "do" ~ expression* ~ "end" } methodblockstatic = { "do" ~ expression* ~ "end" }
methodblockinstance = { "do" ~ instance_espression* ~ "end" }
methodrval = { (":" ~ typespec)? } methodrval = { (":" ~ typespec)? }
defpublic = { "def" ~ methodname ~ methodargs ~ methodrval ~ methodblock } defpublic = { "def" ~ methodname ~ methodargs ~ methodrval ~ methodblockinstance }
defprivate = { "defp" ~ methodname ~ methodargs ~ methodrval ~ methodblock } defprivate = { "defp" ~ methodname ~ methodargs ~ methodrval ~ methodblockinstance }
defstatic = { "defs" ~ methodname ~ methodargs ~ methodrval ~ methodblock } defstatic = { "defs" ~ methodname ~ methodargs ~ methodrval ~ methodblockstatic }
typespec = { typename ~ ("+" ~ typename)* } typespec = { typename ~ ("+" ~ typename)* }
@ -51,6 +53,14 @@ literal = _{ constructor | map | array | typename | string |
ident = @{ !reserved ~ 'a'..'z' ~ ('a'..'z' | 'A'..'Z' | "_")* } ident = @{ !reserved ~ 'a'..'z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
keyword = @{ ident ~ ":" } keyword = @{ ident ~ ":" }
if_expression = { "if" ~ instance_espression ~ if_positive ~ (if_negative | "end") }
if_positive = { "do" ~ instance_espression* }
if_negative = { "else" ~ instance_espression* }
property_get = @{ "@" ~ ident }
property_set = { "@{" ~ (property_set_pair ~ ("," ~ property_set_pair)*) ~ "}" }
property_set_pair = { keyword ~ instance_espression }
constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" } constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" }
constructor_property = { keyword ~ expression } constructor_property = { keyword ~ expression }