Add a bunch more IR stuff and anonymous functions.
This commit is contained in:
parent
781832eb7d
commit
bd2177940c
10 changed files with 444 additions and 80 deletions
|
@ -1,4 +1,6 @@
|
||||||
use crate::error::CompileError;
|
use crate::error::CompileError;
|
||||||
|
use crate::function::{Clause, Function, FunctionIdx};
|
||||||
|
use crate::ir::IR;
|
||||||
use crate::location::Location;
|
use crate::location::Location;
|
||||||
use crate::stable::{StringIdx, StringTable};
|
use crate::stable::{StringIdx, StringTable};
|
||||||
use crate::ty::{Ty, TyIdx};
|
use crate::ty::{Ty, TyIdx};
|
||||||
|
@ -9,20 +11,23 @@ pub struct Context {
|
||||||
errors: Vec<CompileError>,
|
errors: Vec<CompileError>,
|
||||||
strings: StringTable,
|
strings: StringTable,
|
||||||
types: Vec<Ty>,
|
types: Vec<Ty>,
|
||||||
|
functions: Vec<Function>,
|
||||||
current_file: StringIdx,
|
current_file: StringIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(path: &str) -> Context {
|
pub fn new(path: &str) -> Context {
|
||||||
let errors = Vec::default();
|
|
||||||
let mut strings = StringTable::default();
|
let mut strings = StringTable::default();
|
||||||
let types = Vec::default();
|
|
||||||
let current_file = strings.intern(path);
|
let current_file = strings.intern(path);
|
||||||
|
let errors = Vec::default();
|
||||||
|
let functions = Vec::default();
|
||||||
|
let types = Vec::default();
|
||||||
Context {
|
Context {
|
||||||
|
current_file,
|
||||||
errors,
|
errors,
|
||||||
|
functions,
|
||||||
strings,
|
strings,
|
||||||
types,
|
types,
|
||||||
current_file,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,20 +95,37 @@ impl Context {
|
||||||
idx.into()
|
idx.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unknown_type(&mut self, location: Location) -> TyIdx {
|
||||||
|
let idx = self.types.len();
|
||||||
|
let ty = Ty::unknown_type(location);
|
||||||
|
self.types.push(ty);
|
||||||
|
idx.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_type(&self, idx: &TyIdx) -> Option<&Ty> {
|
pub fn get_type(&self, idx: &TyIdx) -> Option<&Ty> {
|
||||||
self.types.get(usize::from(idx))
|
self.types.get(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define_function(&mut self, function: Function) -> FunctionIdx {
|
||||||
|
let idx = self.functions.len();
|
||||||
|
self.functions.push(function);
|
||||||
|
idx.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_function(&self, idx: FunctionIdx) -> Option<&Function> {
|
||||||
|
self.functions.get(usize::from(idx))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn find_type(&mut self, name: &str) -> Option<&Ty> {
|
pub fn find_type(&mut self, name: &str) -> Option<&Ty> {
|
||||||
let name = self.constant_string(name);
|
let name = self.constant_string(name);
|
||||||
self.types.iter().find(|ty| ty.name() == Some(name.clone()))
|
self.types.iter().find(|ty| ty.name() == Some(name.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn location(&self, location: &InputLocation) -> Location {
|
|
||||||
let path = self.strings.get(self.current_file.clone()).unwrap();
|
|
||||||
Location::new(location.clone(), path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
83
huia-compiler/src/function.rs
Normal file
83
huia-compiler/src/function.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
use crate::ir::IR;
|
||||||
|
use crate::stable::StringIdx;
|
||||||
|
use crate::ty::TyIdx;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Function {
|
||||||
|
clauses: Vec<Clause>,
|
||||||
|
return_type: TyIdx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new(return_type: TyIdx) -> Function {
|
||||||
|
Function {
|
||||||
|
return_type,
|
||||||
|
clauses: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, clause: Clause) {
|
||||||
|
self.clauses.push(clause);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.clauses.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Clause {
|
||||||
|
arguments: Vec<(StringIdx, TyIdx)>,
|
||||||
|
body: Vec<IR>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FunctionIdx(usize);
|
||||||
|
|
||||||
|
impl From<usize> for FunctionIdx {
|
||||||
|
fn from(i: usize) -> FunctionIdx {
|
||||||
|
FunctionIdx(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FunctionIdx> for usize {
|
||||||
|
fn from(i: FunctionIdx) -> usize {
|
||||||
|
i.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&FunctionIdx> for usize {
|
||||||
|
fn from(i: &FunctionIdx) -> usize {
|
||||||
|
i.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_new() {
|
||||||
|
let rt = TyIdx::from(13);
|
||||||
|
let mut fun = Function::new(rt);
|
||||||
|
assert!(fun.is_empty());
|
||||||
|
|
||||||
|
let clause = Clause::new(Vec::new());
|
||||||
|
fun.push(clause);
|
||||||
|
|
||||||
|
assert!(!fun.is_empty());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
use crate::function::{Clause, Function};
|
||||||
use crate::ir::{Val, IR};
|
use crate::ir::{Val, IR};
|
||||||
|
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};
|
||||||
|
|
||||||
|
@ -14,6 +16,10 @@ struct Builder {
|
||||||
|
|
||||||
/// Type stack - used to track which type is currently being defined.
|
/// Type stack - used to track which type is currently being defined.
|
||||||
ty_stack: Vec<TyIdx>,
|
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 {
|
||||||
|
@ -232,6 +238,55 @@ impl Builder {
|
||||||
|
|
||||||
self.pop_ty();
|
self.pop_ty();
|
||||||
}
|
}
|
||||||
|
NodeType::Function => {
|
||||||
|
let function = node.function().unwrap();
|
||||||
|
let location = context.location(&node.location());
|
||||||
|
let return_type = context.unknown_type(location);
|
||||||
|
let mut fun = Function::new(return_type);
|
||||||
|
|
||||||
|
for clause in function.value_ref() {
|
||||||
|
let arguments: Vec<(StringIdx, TyIdx)> = clause
|
||||||
|
.arguments()
|
||||||
|
.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();
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
for node in clause.body() {
|
||||||
|
self.build(node.clone(), &mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun.push(self.pop_clause().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = context.define_function(fun);
|
||||||
|
self.push_ir(IR::Function(idx));
|
||||||
|
}
|
||||||
|
// NodeType::PublicMethod => {
|
||||||
|
// let (name, args, typespec, body) = node.public_method().unwrap();
|
||||||
|
|
||||||
|
// let name = context.constant_string(name.value_ref().as_str());
|
||||||
|
// let location = context.location(&node.location());
|
||||||
|
// }
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,6 +311,27 @@ impl Builder {
|
||||||
let len = self.ty_stack.len();
|
let len = self.ty_stack.len();
|
||||||
self.ty_stack.get(len - 1)
|
self.ty_stack.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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -435,4 +511,18 @@ mod test {
|
||||||
assert!(context.find_type("TimeMachine").is_some());
|
assert!(context.find_type("TimeMachine").is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_anonymous_function() {
|
||||||
|
let term = Term::input(r#"fn (speed: Integer) do "WAT" end"#).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_function());
|
||||||
|
|
||||||
|
let fun = context
|
||||||
|
.get_function(ir.function().unwrap().clone())
|
||||||
|
.unwrap();
|
||||||
|
assert!(!fun.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod builder;
|
mod builder;
|
||||||
|
|
||||||
|
use crate::function::FunctionIdx;
|
||||||
use crate::stable::StringIdx;
|
use crate::stable::StringIdx;
|
||||||
use crate::ty::TyIdx;
|
use crate::ty::TyIdx;
|
||||||
use huia_parser::ast::binary::Operator as BinOp;
|
use huia_parser::ast::binary::Operator as BinOp;
|
||||||
|
@ -18,6 +19,7 @@ pub enum IR {
|
||||||
Unary(UnOp, Box<IR>),
|
Unary(UnOp, Box<IR>),
|
||||||
Call(StringIdx, Vec<IR>),
|
Call(StringIdx, Vec<IR>),
|
||||||
Declaration(StringIdx, Box<IR>),
|
Declaration(StringIdx, Box<IR>),
|
||||||
|
Function(FunctionIdx),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IR {
|
impl IR {
|
||||||
|
@ -69,6 +71,20 @@ impl IR {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_function(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
IR::Function(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function(&self) -> Option<&FunctionIdx> {
|
||||||
|
match self {
|
||||||
|
IR::Function(ref idx) => Some(idx),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A constant value.
|
/// A constant value.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod context;
|
mod context;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod function;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod location;
|
mod location;
|
||||||
mod stable;
|
mod stable;
|
||||||
|
|
|
@ -56,6 +56,15 @@ impl Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unknown_type(location: Location) -> Ty {
|
||||||
|
Ty {
|
||||||
|
name: None,
|
||||||
|
location,
|
||||||
|
kind: TyKind::Unresolved,
|
||||||
|
inner: TyInner::Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Option<StringIdx> {
|
pub fn name(&self) -> Option<StringIdx> {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
95
huia-parser/src/ast/function.rs
Normal file
95
huia-parser/src/ast/function.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use crate::ast::{Identifier, Location, Term, TypeSpec, Value};
|
||||||
|
use crate::grammar::Rule;
|
||||||
|
use crate::input_location::InputLocation;
|
||||||
|
use pest::iterators::Pair;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Function {
|
||||||
|
clauses: Vec<Clause>,
|
||||||
|
location: InputLocation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value for Function {
|
||||||
|
type Item = Vec<Clause>;
|
||||||
|
|
||||||
|
fn value(self) -> Self::Item {
|
||||||
|
self.clauses
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_ref(&self) -> &Self::Item {
|
||||||
|
&self.clauses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Location for Function {
|
||||||
|
fn location(&self) -> &InputLocation {
|
||||||
|
&self.location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Pair<'a, Rule>> for Function {
|
||||||
|
fn from(pair: Pair<'a, Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::function => {
|
||||||
|
let clauses = pair.clone().into_inner().map(|p| Clause::from(p)).collect();
|
||||||
|
let location = InputLocation::from(pair.into_span());
|
||||||
|
Function { clauses, location }
|
||||||
|
}
|
||||||
|
_ => unreachable!("Expected pair to be a Function"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Clause {
|
||||||
|
arguments: Vec<(Identifier, TypeSpec)>,
|
||||||
|
body: Vec<Term>,
|
||||||
|
location: InputLocation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clause {
|
||||||
|
pub fn arguments(&self) -> &Vec<(Identifier, TypeSpec)> {
|
||||||
|
&self.arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body(&self) -> &Vec<Term> {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Location for Clause {
|
||||||
|
fn location(&self) -> &InputLocation {
|
||||||
|
&self.location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Pair<'a, Rule>> for Clause {
|
||||||
|
fn from(pair: Pair<'a, Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::function_clause => {
|
||||||
|
println!("clause = {:#?}", pair);
|
||||||
|
let mut inner = pair.clone().into_inner();
|
||||||
|
let arguments = inner
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.into_inner()
|
||||||
|
.map(|p| {
|
||||||
|
println!("p = {:?}", 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 body = inner.next().unwrap().into_inner().map(Term::from).collect();
|
||||||
|
let location = InputLocation::from(pair);
|
||||||
|
Clause {
|
||||||
|
arguments,
|
||||||
|
body,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!("Expected pair to be a Function Clause"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ mod atom;
|
||||||
pub mod binary;
|
pub mod binary;
|
||||||
mod boolean;
|
mod boolean;
|
||||||
mod float;
|
mod float;
|
||||||
|
mod function;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod integer;
|
mod integer;
|
||||||
mod local;
|
mod local;
|
||||||
|
@ -15,6 +16,7 @@ pub use atom::Atom;
|
||||||
pub use binary::Binary;
|
pub use binary::Binary;
|
||||||
pub use boolean::Boolean;
|
pub use boolean::Boolean;
|
||||||
pub use float::Float;
|
pub use float::Float;
|
||||||
|
pub use function::Function;
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use integer::Integer;
|
pub use integer::Integer;
|
||||||
pub use local::Local;
|
pub use local::Local;
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub enum NodeType {
|
||||||
Call,
|
Call,
|
||||||
Declaration,
|
Declaration,
|
||||||
Local,
|
Local,
|
||||||
|
Function,
|
||||||
|
|
||||||
TypeDef,
|
TypeDef,
|
||||||
TraitDef,
|
TraitDef,
|
||||||
|
@ -54,24 +55,21 @@ enum Inner {
|
||||||
Binary(Binary, Box<Term>, Box<Term>),
|
Binary(Binary, Box<Term>, Box<Term>),
|
||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
Call(Identifier, Vec<Term>),
|
Call(Identifier, Vec<Term>),
|
||||||
Ty(Ty),
|
|
||||||
Constructor(Ty, Vec<(Identifier, Term)>),
|
Constructor(Ty, Vec<(Identifier, Term)>),
|
||||||
Declaration(Identifier, Box<Term>),
|
Declaration(Identifier, Box<Term>),
|
||||||
Float(Float),
|
Float(Float),
|
||||||
|
Function(Function),
|
||||||
|
ImplDef(Ty, Vec<Term>),
|
||||||
Integer(Integer),
|
Integer(Integer),
|
||||||
Local(Local),
|
Local(Local),
|
||||||
Map(Vec<(Term, Term)>),
|
Map(Vec<(Term, Term)>),
|
||||||
String(String),
|
PrivateMethod(
|
||||||
TypeDef(Ty, Vec<(Identifier, TypeSpec)>, Vec<Term>),
|
|
||||||
TraitDef(Ty, Option<TypeSpec>, Vec<Term>),
|
|
||||||
ImplDef(Ty, Vec<Term>),
|
|
||||||
PublicMethod(
|
|
||||||
Identifier,
|
Identifier,
|
||||||
Vec<(Identifier, TypeSpec)>,
|
Vec<(Identifier, TypeSpec)>,
|
||||||
Option<TypeSpec>,
|
Option<TypeSpec>,
|
||||||
Vec<Term>,
|
Vec<Term>,
|
||||||
),
|
),
|
||||||
PrivateMethod(
|
PublicMethod(
|
||||||
Identifier,
|
Identifier,
|
||||||
Vec<(Identifier, TypeSpec)>,
|
Vec<(Identifier, TypeSpec)>,
|
||||||
Option<TypeSpec>,
|
Option<TypeSpec>,
|
||||||
|
@ -83,6 +81,10 @@ enum Inner {
|
||||||
Option<TypeSpec>,
|
Option<TypeSpec>,
|
||||||
Vec<Term>,
|
Vec<Term>,
|
||||||
),
|
),
|
||||||
|
String(String),
|
||||||
|
TraitDef(Ty, Option<TypeSpec>, Vec<Term>),
|
||||||
|
Ty(Ty),
|
||||||
|
TypeDef(Ty, Vec<(Identifier, TypeSpec)>, Vec<Term>),
|
||||||
Unary(Unary, Box<Term>),
|
Unary(Unary, Box<Term>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,23 +126,24 @@ impl Term {
|
||||||
|
|
||||||
pub fn node_type(&self) -> NodeType {
|
pub fn node_type(&self) -> NodeType {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Inner::Array(_) => NodeType::Array,
|
Inner::Array(..) => NodeType::Array,
|
||||||
Inner::Atom(_) => NodeType::Atom,
|
Inner::Atom(..) => NodeType::Atom,
|
||||||
Inner::Boolean(_) => NodeType::Boolean,
|
Inner::Boolean(..) => NodeType::Boolean,
|
||||||
Inner::Binary(_, _, _) => NodeType::Binary,
|
Inner::Binary(..) => NodeType::Binary,
|
||||||
Inner::Call(_, _) => NodeType::Call,
|
Inner::Call(..) => NodeType::Call,
|
||||||
Inner::Ty(_) => NodeType::Ty,
|
Inner::Ty(..) => NodeType::Ty,
|
||||||
Inner::Constructor(_, _) => NodeType::Constructor,
|
Inner::Constructor(..) => NodeType::Constructor,
|
||||||
Inner::Declaration(_, _) => NodeType::Declaration,
|
Inner::Declaration(..) => NodeType::Declaration,
|
||||||
Inner::Float(_) => NodeType::Float,
|
Inner::Function(..) => NodeType::Function,
|
||||||
Inner::Integer(_) => NodeType::Integer,
|
Inner::Float(..) => NodeType::Float,
|
||||||
Inner::Local(_) => NodeType::Local,
|
Inner::Integer(..) => NodeType::Integer,
|
||||||
Inner::Map(_) => NodeType::Map,
|
Inner::Local(..) => NodeType::Local,
|
||||||
Inner::String(_) => NodeType::String,
|
Inner::Map(..) => NodeType::Map,
|
||||||
Inner::Unary(_, _) => NodeType::Unary,
|
Inner::String(..) => NodeType::String,
|
||||||
Inner::TypeDef(_, _, _) => NodeType::TypeDef,
|
Inner::Unary(..) => NodeType::Unary,
|
||||||
Inner::TraitDef(_, _, _) => NodeType::TraitDef,
|
Inner::TypeDef(..) => NodeType::TypeDef,
|
||||||
Inner::ImplDef(_, _) => NodeType::ImplDef,
|
Inner::TraitDef(..) => NodeType::TraitDef,
|
||||||
|
Inner::ImplDef(..) => NodeType::ImplDef,
|
||||||
Inner::PublicMethod(_, _, _, _) => NodeType::PublicMethod,
|
Inner::PublicMethod(_, _, _, _) => NodeType::PublicMethod,
|
||||||
Inner::PrivateMethod(_, _, _, _) => NodeType::PrivateMethod,
|
Inner::PrivateMethod(_, _, _, _) => NodeType::PrivateMethod,
|
||||||
Inner::StaticMethod(_, _, _, _) => NodeType::StaticMethod,
|
Inner::StaticMethod(_, _, _, _) => NodeType::StaticMethod,
|
||||||
|
@ -217,6 +220,13 @@ impl Term {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn function(&self) -> Option<&Function> {
|
||||||
|
match self.inner {
|
||||||
|
Inner::Function(ref function) => Some(function),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn public_method(
|
pub fn public_method(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<(
|
) -> Option<(
|
||||||
|
@ -402,6 +412,10 @@ impl<'a> From<Pair<'a, Rule>> for Term {
|
||||||
location: InputLocation::from(pair.clone()),
|
location: InputLocation::from(pair.clone()),
|
||||||
inner: Inner::Float(Float::from(pair)),
|
inner: Inner::Float(Float::from(pair)),
|
||||||
},
|
},
|
||||||
|
Rule::function => Term {
|
||||||
|
location: InputLocation::from(pair.clone()),
|
||||||
|
inner: Inner::Function(Function::from(pair)),
|
||||||
|
},
|
||||||
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()),
|
||||||
|
@ -977,6 +991,33 @@ mod test {
|
||||||
assert_eq!(rhs2.integer().unwrap().value_ref(), &4);
|
assert_eq!(rhs2.integer().unwrap().value_ref(), &4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_anonymous_function() {
|
||||||
|
let terms = Term::input(
|
||||||
|
r#"
|
||||||
|
fn (speed: Integer) do
|
||||||
|
"WAT"
|
||||||
|
end,
|
||||||
|
(speed: Float) do
|
||||||
|
"WAT"
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let function = terms[0].function().unwrap();
|
||||||
|
let clauses = function.value_ref();
|
||||||
|
assert_eq!(clauses.len(), 2);
|
||||||
|
|
||||||
|
let clause0 = &clauses[0];
|
||||||
|
let clause1 = &clauses[1];
|
||||||
|
|
||||||
|
assert_eq!(clause0.arguments().len(), 1);
|
||||||
|
assert_eq!(clause0.body().len(), 1);
|
||||||
|
assert_eq!(clause1.arguments().len(), 1);
|
||||||
|
assert_eq!(clause1.body().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn test_acceptance() {
|
// fn test_acceptance() {
|
||||||
// let terms = Term::input(
|
// let terms = Term::input(
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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 = _{ call | declaration | unary | literal | local | braced_expression }
|
expression_inner = _{ function | call | declaration | unary | literal | local | braced_expression }
|
||||||
braced_expression = _{ "(" ~ expression ~ ")" }
|
braced_expression = _{ "(" ~ expression ~ ")" }
|
||||||
|
|
||||||
declaration = { "let" ~ ident ~ assign ~ expression }
|
declaration = { "let" ~ ident ~ assign ~ expression }
|
||||||
|
@ -64,6 +64,11 @@ atom = @{ ":" ~ ident }
|
||||||
typename = @{ typename_name ~ ("." ~ typename_name)* }
|
typename = @{ typename_name ~ ("." ~ typename_name)* }
|
||||||
typename_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
|
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" }
|
||||||
|
|
||||||
float = ${ float_characteristic ~ "." ~ float_mantissa }
|
float = ${ float_characteristic ~ "." ~ float_mantissa }
|
||||||
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }
|
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }
|
||||||
float_mantissa = { ('0'..'9')+ }
|
float_mantissa = { ('0'..'9')+ }
|
||||||
|
|
Reference in a new issue