Build IR
This commit is contained in:
parent
bd2177940c
commit
30fdff315b
13 changed files with 1029 additions and 493 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"spellright.language": "en-NZ",
|
"spellright.language": [
|
||||||
|
"en"
|
||||||
|
],
|
||||||
"spellright.documentTypes": [
|
"spellright.documentTypes": [
|
||||||
"markdown",
|
"markdown",
|
||||||
"latex"
|
"latex"
|
||||||
|
|
25
huia-compiler/src/block.rs
Normal file
25
huia-compiler/src/block.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
self.body.push(ir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
103
huia-compiler/src/method.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
||||||
|
|
Reference in a new issue