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": [
|
||||
"markdown",
|
||||
"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::ir::IR;
|
||||
use crate::location::Location;
|
||||
use crate::method::{Method, MethodIdx};
|
||||
use crate::stable::{StringIdx, StringTable};
|
||||
use crate::ty::{Ty, TyIdx};
|
||||
use huia_parser::input_location::InputLocation;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
current_file: StringIdx,
|
||||
errors: Vec<CompileError>,
|
||||
functions: Vec<Function>,
|
||||
methods: Vec<Method>,
|
||||
strings: StringTable,
|
||||
types: Vec<Ty>,
|
||||
functions: Vec<Function>,
|
||||
current_file: StringIdx,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
@ -22,10 +24,12 @@ impl Context {
|
|||
let errors = Vec::default();
|
||||
let functions = Vec::default();
|
||||
let types = Vec::default();
|
||||
let methods = Vec::default();
|
||||
Context {
|
||||
current_file,
|
||||
errors,
|
||||
functions,
|
||||
methods,
|
||||
strings,
|
||||
types,
|
||||
}
|
||||
|
@ -106,6 +110,10 @@ impl Context {
|
|||
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 {
|
||||
let path = self.strings.get(self.current_file.clone()).unwrap();
|
||||
Location::new(location.clone(), path)
|
||||
|
@ -117,6 +125,12 @@ impl Context {
|
|||
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> {
|
||||
self.functions.get(usize::from(idx))
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ impl Function {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, clause: Clause) {
|
||||
self.clauses.push(clause);
|
||||
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 {
|
||||
|
@ -32,19 +34,12 @@ pub struct Clause {
|
|||
}
|
||||
|
||||
impl Clause {
|
||||
pub fn new(arguments: Vec<(StringIdx, TyIdx)>) -> Clause {
|
||||
Clause {
|
||||
arguments,
|
||||
body: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, ir: IR) {
|
||||
self.body.push(ir);
|
||||
pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: Vec<IR>) -> Clause {
|
||||
Clause { arguments, body }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FunctionIdx(usize);
|
||||
|
||||
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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -75,8 +91,7 @@ mod test {
|
|||
let mut fun = Function::new(rt);
|
||||
assert!(fun.is_empty());
|
||||
|
||||
let clause = Clause::new(Vec::new());
|
||||
fun.push(clause);
|
||||
fun.push(Vec::new(), Vec::new());
|
||||
|
||||
assert!(!fun.is_empty());
|
||||
}
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
use crate::block::Block;
|
||||
use crate::context::Context;
|
||||
use crate::function::{Clause, Function};
|
||||
use crate::function::Function;
|
||||
use crate::ir::{Val, IR};
|
||||
use crate::method::Method;
|
||||
use crate::stable::StringIdx;
|
||||
use crate::ty::TyIdx;
|
||||
use huia_parser::ast::{Location, NodeType, Term, Value};
|
||||
|
||||
/// The Builder is a simple stack machine for converting AST into IR.
|
||||
/// 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.
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Debug)]
|
||||
struct Builder {
|
||||
/// The IR stack - used to compose intermediate values.
|
||||
ir_stack: Vec<IR>,
|
||||
|
||||
/// 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>,
|
||||
blocks: Vec<Block>,
|
||||
types: Vec<TyIdx>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
|
@ -28,47 +23,6 @@ impl Builder {
|
|||
/// Any IR will be on the Builder's stack.
|
||||
pub fn build(&mut self, node: Term, mut context: &mut Context) {
|
||||
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 => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Array");
|
||||
let location = context.location(&node.location());
|
||||
|
@ -85,24 +39,19 @@ impl Builder {
|
|||
.collect();
|
||||
self.push_ir(IR::Constant(ty, Val::Array(elements)));
|
||||
}
|
||||
NodeType::Map => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Map");
|
||||
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 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)));
|
||||
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::Binary => {
|
||||
let (op, lhs, rhs) = node.binary().unwrap();
|
||||
|
@ -112,6 +61,19 @@ impl Builder {
|
|||
let lhs = self.pop_ir().unwrap();
|
||||
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 => {
|
||||
let (ty, props) = node.constructor().unwrap();
|
||||
let ty_idx = context.constant_string(ty.value_ref().as_str());
|
||||
|
@ -123,120 +85,25 @@ impl Builder {
|
|||
.map(|(key, value)| {
|
||||
let key = context.constant_string(key.value_ref().as_str());
|
||||
self.build(value.clone(), &mut context);
|
||||
let value = self.ir_stack.pop().unwrap();
|
||||
let value = self.pop_ir().unwrap();
|
||||
(key, value)
|
||||
})
|
||||
.collect();
|
||||
self.push_ir(IR::Constructor(ty, elements));
|
||||
}
|
||||
NodeType::Unary => {
|
||||
let (op, rhs) = node.unary().unwrap();
|
||||
NodeType::Declaration => {
|
||||
let (name, rhs) = node.declaration().unwrap();
|
||||
let name = context.constant_string(name.value_ref().as_str());
|
||||
self.build(rhs.clone(), &mut context);
|
||||
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 => {
|
||||
let (name, args) = node.call().unwrap();
|
||||
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());
|
||||
NodeType::Float => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Float");
|
||||
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());
|
||||
|
||||
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();
|
||||
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::Function => {
|
||||
let function = node.function().unwrap();
|
||||
|
@ -265,72 +132,407 @@ impl Builder {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// FIXME: We need to put the built nodes into a scope
|
||||
// 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));
|
||||
self.push_block();
|
||||
|
||||
for node in clause.body() {
|
||||
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);
|
||||
self.push_ir(IR::Function(idx));
|
||||
let fun_idx = context.define_function(fun);
|
||||
self.push_ir(IR::Function(fun_idx));
|
||||
}
|
||||
// NodeType::PublicMethod => {
|
||||
// let (name, args, typespec, body) = node.public_method().unwrap();
|
||||
NodeType::If => {
|
||||
let (test, positive, negative) = node.if_expr().unwrap();
|
||||
let location = context.location(&node.location());
|
||||
|
||||
// let name = context.constant_string(name.value_ref().as_str());
|
||||
// let location = context.location(&node.location());
|
||||
// }
|
||||
_ => (),
|
||||
self.build(test.clone(), &mut context);
|
||||
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) {
|
||||
self.ir_stack.push(ir);
|
||||
fn push_block(&mut self) {
|
||||
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> {
|
||||
self.ir_stack.pop()
|
||||
self.peek_block_mut().unwrap().pop()
|
||||
}
|
||||
|
||||
pub fn push_ty(&mut self, ty: TyIdx) {
|
||||
self.ty_stack.push(ty);
|
||||
fn push_ty(&mut self, idx: TyIdx) {
|
||||
self.types.push(idx);
|
||||
}
|
||||
|
||||
pub fn pop_ty(&mut self) -> Option<TyIdx> {
|
||||
self.ty_stack.pop()
|
||||
fn pop_ty(&mut self) -> Option<TyIdx> {
|
||||
self.types.pop()
|
||||
}
|
||||
|
||||
pub fn peek_ty(&self) -> Option<&TyIdx> {
|
||||
let len = self.ty_stack.len();
|
||||
self.ty_stack.get(len - 1)
|
||||
fn peek_ty(&mut self) -> Option<&TyIdx> {
|
||||
let len = self.types.len();
|
||||
self.types.get(len - 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_fn(&mut self, fun: Function) {
|
||||
self.fn_stack.push(fun);
|
||||
}
|
||||
|
||||
pub fn pop_fn(&mut self) -> Option<Function> {
|
||||
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()
|
||||
impl Default for Builder {
|
||||
fn default() -> Builder {
|
||||
let blocks = vec![Block::default()];
|
||||
let types = Vec::default();
|
||||
Builder { blocks, types }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,19 +660,21 @@ mod test {
|
|||
let mut builder = Builder::default();
|
||||
let mut context = Context::test();
|
||||
builder.build(term, &mut context);
|
||||
let ir = builder.pop_ir().unwrap();
|
||||
assert!(ir.is_call());
|
||||
let call = builder.pop_ir().unwrap();
|
||||
let receiver = builder.pop_ir().unwrap();
|
||||
assert!(call.is_call());
|
||||
assert!(receiver.is_get_local());
|
||||
assert!(context.find_type("Huia.Native.Integer").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_declaration() {
|
||||
fn test_set_local() {
|
||||
let term = Term::input(r#" let x = 123 "#).unwrap()[0].clone();
|
||||
let mut builder = Builder::default();
|
||||
let mut context = Context::test();
|
||||
builder.build(term, &mut context);
|
||||
let ir = builder.pop_ir().unwrap();
|
||||
assert!(ir.is_declaration());
|
||||
assert!(ir.is_set_local());
|
||||
assert!(context.find_type("Huia.Native.Integer").is_some());
|
||||
}
|
||||
|
||||
|
@ -525,4 +729,46 @@ mod test {
|
|||
.unwrap();
|
||||
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:
|
||||
/// IR should have a location too if possible.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum IR {
|
||||
/// Call top of the stack with arguments.
|
||||
Call(Vec<IR>),
|
||||
/// A constant value of the specified type.
|
||||
Constant(TyIdx, Val),
|
||||
TypeReference(TyIdx),
|
||||
Infix(BinOp, Box<(IR, IR)>),
|
||||
/// Construct an instance of type with the provided properties.
|
||||
Constructor(TyIdx, Vec<(StringIdx, IR)>),
|
||||
Unary(UnOp, Box<IR>),
|
||||
Call(StringIdx, Vec<IR>),
|
||||
Declaration(StringIdx, Box<IR>),
|
||||
/// Reference an anonymous function from the context.
|
||||
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 {
|
||||
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 {
|
||||
match self {
|
||||
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 {
|
||||
match self {
|
||||
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 {
|
||||
match self {
|
||||
IR::Function(..) => true,
|
||||
|
@ -79,16 +74,51 @@ impl IR {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn function(&self) -> Option<&FunctionIdx> {
|
||||
pub fn is_get_local(&self) -> bool {
|
||||
match self {
|
||||
IR::Function(ref idx) => Some(idx),
|
||||
_ => None,
|
||||
IR::GetLocal(..) => true,
|
||||
_ => 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.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Val {
|
||||
Atom(StringIdx),
|
||||
Boolean(bool),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
mod block;
|
||||
mod context;
|
||||
mod error;
|
||||
mod function;
|
||||
mod ir;
|
||||
mod location;
|
||||
mod method;
|
||||
mod stable;
|
||||
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::stable::StringIdx;
|
||||
use std::fmt;
|
||||
|
@ -13,6 +14,7 @@ pub struct Ty {
|
|||
location: Location,
|
||||
kind: TyKind,
|
||||
inner: TyInner,
|
||||
body: Vec<IR>,
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
@ -26,6 +28,7 @@ impl Ty {
|
|||
location,
|
||||
kind: TyKind::Type,
|
||||
inner: TyInner::Type { properties },
|
||||
body: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +38,7 @@ impl Ty {
|
|||
location,
|
||||
kind: TyKind::Trait,
|
||||
inner: TyInner::Trait { dependencies },
|
||||
body: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +48,7 @@ impl Ty {
|
|||
location,
|
||||
kind: TyKind::Unresolved,
|
||||
inner: TyInner::Empty,
|
||||
body: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +58,7 @@ impl Ty {
|
|||
location,
|
||||
kind: TyKind::Impl,
|
||||
inner: TyInner::Impl { ty, tr },
|
||||
body: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +68,7 @@ impl Ty {
|
|||
location,
|
||||
kind: TyKind::Unresolved,
|
||||
inner: TyInner::Empty,
|
||||
body: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,15 @@ impl<'a> From<Pair<'a, Rule>> for Identifier {
|
|||
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!(
|
||||
"Expected pair to be an Identifier (received {:?})",
|
||||
pair.as_rule()
|
||||
|
|
|
@ -37,8 +37,11 @@ pub enum NodeType {
|
|||
|
||||
Call,
|
||||
Declaration,
|
||||
Local,
|
||||
Function,
|
||||
If,
|
||||
Local,
|
||||
PropertyGet,
|
||||
PropertySet,
|
||||
|
||||
TypeDef,
|
||||
TraitDef,
|
||||
|
@ -59,6 +62,7 @@ enum Inner {
|
|||
Declaration(Identifier, Box<Term>),
|
||||
Float(Float),
|
||||
Function(Function),
|
||||
If(Box<Term>, Vec<Term>, Vec<Term>),
|
||||
ImplDef(Ty, Vec<Term>),
|
||||
Integer(Integer),
|
||||
Local(Local),
|
||||
|
@ -69,6 +73,8 @@ enum Inner {
|
|||
Option<TypeSpec>,
|
||||
Vec<Term>,
|
||||
),
|
||||
PropertyGet(Identifier),
|
||||
PropertySet(Vec<(Identifier, Term)>),
|
||||
PublicMethod(
|
||||
Identifier,
|
||||
Vec<(Identifier, TypeSpec)>,
|
||||
|
@ -136,9 +142,12 @@ impl Term {
|
|||
Inner::Declaration(..) => NodeType::Declaration,
|
||||
Inner::Function(..) => NodeType::Function,
|
||||
Inner::Float(..) => NodeType::Float,
|
||||
Inner::If(..) => NodeType::If,
|
||||
Inner::Integer(..) => NodeType::Integer,
|
||||
Inner::Local(..) => NodeType::Local,
|
||||
Inner::Map(..) => NodeType::Map,
|
||||
Inner::PropertyGet(..) => NodeType::PropertyGet,
|
||||
Inner::PropertySet(..) => NodeType::PropertySet,
|
||||
Inner::String(..) => NodeType::String,
|
||||
Inner::Unary(..) => NodeType::Unary,
|
||||
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)>)> {
|
||||
match self.inner {
|
||||
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)> {
|
||||
match self.inner {
|
||||
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> {
|
||||
match self.inner {
|
||||
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> {
|
||||
match self.inner {
|
||||
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)> {
|
||||
match self.inner {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
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 {
|
||||
location: InputLocation::from(pair.clone()),
|
||||
inner: Inner::Float(Float::from(pair)),
|
||||
|
@ -416,6 +518,38 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
|||
location: InputLocation::from(pair.clone()),
|
||||
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::integer => Term {
|
||||
location: InputLocation::from(pair.clone()),
|
||||
|
@ -447,6 +581,26 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
|||
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 {
|
||||
location: InputLocation::from(pair.clone()),
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
Rule::traitdef => {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
Rule::typedef => {
|
||||
let mut inner = pair.clone().into_inner();
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,15 @@ impl<'a> From<pest::error::Error<Rule>> for ParseError {
|
|||
pest::error::ErrorVariant::ParsingError {
|
||||
ref positives,
|
||||
ref negatives,
|
||||
} => ParseError::PestError {
|
||||
positives: positives.clone(),
|
||||
negatives: negatives.clone(),
|
||||
location: InputLocation::from(pest.location),
|
||||
},
|
||||
} => {
|
||||
// FIXME: Remove when we have real error formatting.
|
||||
println!("Pest Error: {}", pest);
|
||||
ParseError::PestError {
|
||||
positives: positives.clone(),
|
||||
negatives: negatives.clone(),
|
||||
location: InputLocation::from(pest.location),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,71 +3,81 @@ file = _{ SOI ~ definition* ~ EOI }
|
|||
|
||||
WHITESPACE = _{ (" " | "\t" | "\r" | "\n")+ }
|
||||
newline = _{ (" " | "\t")* ~ ("\n" | "\r")+ ~ (" " | "\t")* }
|
||||
reserved = { "end" | "let" | "true" | "false" }
|
||||
reserved = { "end" | "let" | "true" | "false" }
|
||||
|
||||
expression = _{ infix | expression_inner }
|
||||
infix = { expression_inner ~ (binary_operator ~ expression_inner)+ }
|
||||
expression_inner = _{ function | call | declaration | unary | literal | local | braced_expression }
|
||||
infix = { expression_inner ~ (binary_operator ~ expression_inner)+ }
|
||||
expression_inner = _{ if_expression | function | call | declaration | unary | literal | local | braced_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) }
|
||||
|
||||
call = { ident ~ call_arguments }
|
||||
call = { ident ~ call_arguments }
|
||||
call_arguments = _{ "(" ~ (call_argument ~ ("," ~ call_argument)* )? ~ ")" }
|
||||
call_argument = { expression }
|
||||
call_argument = { expression }
|
||||
|
||||
defargs = _{ "(" ~ (defarg ~ ("," ~ defarg)*)? ~ ")" }
|
||||
defarg = { keyword ~ typespec }
|
||||
defarg = { keyword ~ typespec }
|
||||
|
||||
definition = _{ typedef | traitdef }
|
||||
|
||||
typedef = { "type" ~ typename ~ typeprops ~ typedefblock }
|
||||
typeprops = { defargs? }
|
||||
typedefblock = { ("do" ~ (methoddef | impldef)* ~ "end")? }
|
||||
typedef = { "type" ~ typename ~ typeprops ~ typedefblock }
|
||||
typeprops = { defargs? }
|
||||
typedefblock = { ("do" ~ (methoddef | impldef)* ~ "end")? }
|
||||
|
||||
traitdef = { "trait" ~ typename ~ traitdefreqs ~ traitdefblock }
|
||||
traitdefreqs = { (":" ~ typespec)? }
|
||||
traitdefblock = { ("do" ~ methoddef* ~ "end")? }
|
||||
traitdef = { "trait" ~ typename ~ traitdefreqs ~ traitdefblock }
|
||||
traitdefreqs = { (":" ~ typespec)? }
|
||||
traitdefblock = { ("do" ~ methoddef* ~ "end")? }
|
||||
|
||||
impldef = { "impl" ~ typename ~ impldefblock }
|
||||
impldefblock = { ("do" ~ methoddef* ~ "end")? }
|
||||
impldef = { "impl" ~ typename ~ impldefblock }
|
||||
impldefblock = { ("do" ~ methoddef* ~ "end")? }
|
||||
|
||||
methoddef = _{ defpublic | defprivate | defstatic }
|
||||
methodargs = { defargs? }
|
||||
methodargs = { defargs? }
|
||||
methodname = @{ ident ~ ("?")? }
|
||||
methodblock = { "do" ~ expression* ~ "end" }
|
||||
methodrval = { (":" ~ typespec)? }
|
||||
methodblockstatic = { "do" ~ expression* ~ "end" }
|
||||
methodblockinstance = { "do" ~ instance_espression* ~ "end" }
|
||||
methodrval = { (":" ~ typespec)? }
|
||||
|
||||
defpublic = { "def" ~ methodname ~ methodargs ~ methodrval ~ methodblock }
|
||||
defprivate = { "defp" ~ methodname ~ methodargs ~ methodrval ~ methodblock }
|
||||
defstatic = { "defs" ~ methodname ~ methodargs ~ methodrval ~ methodblock }
|
||||
defpublic = { "def" ~ methodname ~ methodargs ~ methodrval ~ methodblockinstance }
|
||||
defprivate = { "defp" ~ methodname ~ methodargs ~ methodrval ~ methodblockinstance }
|
||||
defstatic = { "defs" ~ methodname ~ methodargs ~ methodrval ~ methodblockstatic }
|
||||
|
||||
typespec = { typename ~ ("+" ~ typename)* }
|
||||
typespec = { typename ~ ("+" ~ typename)* }
|
||||
|
||||
literal = _{ constructor | map | array | typename | string | atom | float | integer | boolean }
|
||||
|
||||
ident = @{ !reserved ~ 'a'..'z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
||||
keyword = @{ ident ~ ":" }
|
||||
|
||||
constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" }
|
||||
constructor_property = { keyword ~ expression }
|
||||
if_expression = { "if" ~ instance_espression ~ if_positive ~ (if_negative | "end") }
|
||||
if_positive = { "do" ~ instance_espression* }
|
||||
if_negative = { "else" ~ instance_espression* }
|
||||
|
||||
map = { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" }
|
||||
map_pair = { (keyword | (expression ~ "=>")) ~ expression }
|
||||
property_get = @{ "@" ~ ident }
|
||||
property_set = { "@{" ~ (property_set_pair ~ ("," ~ property_set_pair)*) ~ "}" }
|
||||
property_set_pair = { keyword ~ instance_espression }
|
||||
|
||||
array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" }
|
||||
constructor = { typename ~ "{" ~ (constructor_property ~ ("," ~ constructor_property)*)? ~ "}" }
|
||||
constructor_property = { keyword ~ expression }
|
||||
|
||||
map = { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" }
|
||||
map_pair = { (keyword | (expression ~ "=>")) ~ expression }
|
||||
|
||||
array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" }
|
||||
|
||||
atom = @{ ":" ~ ident }
|
||||
|
||||
typename = @{ typename_name ~ ("." ~ typename_name)* }
|
||||
typename_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
||||
|
||||
function = { "fn" ~ function_clause ~ ("," ~ function_clause)* }
|
||||
function_args = { defargs }
|
||||
function_clause = { function_args ~ function_block }
|
||||
function_block = { "do" ~ expression* ~ "end" }
|
||||
function = { "fn" ~ function_clause ~ ("," ~ function_clause)* }
|
||||
function_args = { defargs }
|
||||
function_clause = { function_args ~ function_block }
|
||||
function_block = { "do" ~ expression* ~ "end" }
|
||||
|
||||
float = ${ float_characteristic ~ "." ~ float_mantissa }
|
||||
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }
|
||||
|
@ -90,7 +100,7 @@ string_delimiter = _{ "\"" }
|
|||
string_unicode = _{ "u" ~ ('0'..'9' | 'a'..'f' | 'A'..'F'){4} }
|
||||
string_escape = _{ "\\" ~ ("\"" | "\\" | "a" | "b" | "f" | "n" | "r" | "t" | "v" | string_unicode) }
|
||||
|
||||
local = { ident }
|
||||
local = { ident }
|
||||
|
||||
exponent = { "**" }
|
||||
multiply = { "*" }
|
||||
|
@ -140,6 +150,6 @@ binary_operator = _{
|
|||
}
|
||||
unary_operator = _{ plus | minus | logical_not }
|
||||
|
||||
boolean = { boolean_true | boolean_false }
|
||||
boolean_true = { "true" }
|
||||
boolean_false = { "false" }
|
||||
boolean = { boolean_true | boolean_false }
|
||||
boolean_true = { "true" }
|
||||
boolean_false = { "false" }
|
||||
|
|
Reference in a new issue