Support for methods. Started support for functions defined in script but not yet ready
This commit is contained in:
parent
419781cfb6
commit
a8fa76c2fc
134
src/engine.rs
134
src/engine.rs
@ -6,7 +6,6 @@ use std::fmt;
|
|||||||
|
|
||||||
use parser::{lex, parse, Expr, Stmt };
|
use parser::{lex, parse, Expr, Stmt };
|
||||||
use fn_register::FnRegister;
|
use fn_register::FnRegister;
|
||||||
//use ops::{add_boxes, sub_boxes, mult_boxes, div_boxes};
|
|
||||||
|
|
||||||
use std::ops::{Add, Sub, Mul, Div};
|
use std::ops::{Add, Sub, Mul, Div};
|
||||||
use std::cmp::{Ord, Eq};
|
use std::cmp::{Ord, Eq};
|
||||||
@ -91,6 +90,7 @@ fn or(x: bool, y: bool) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
|
pub fns_arity_3: HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
pub fns_arity_2: HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
pub fns_arity_2: HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
pub fns_arity_1: HashMap<String, Vec<Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
pub fns_arity_1: HashMap<String, Vec<Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
pub fns_arity_0: HashMap<String, Vec<Box<Fn()->Result<Box<Any>, EvalError>>>>,
|
pub fns_arity_0: HashMap<String, Vec<Box<Fn()->Result<Box<Any>, EvalError>>>>,
|
||||||
@ -98,8 +98,8 @@ pub struct Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
pub fn call_fn_0_arg(&self, name: &str) -> Result<Box<Any>, EvalError> {
|
pub fn call_fn_0_arg(fns_arity_0: &HashMap<String, Vec<Box<Fn()->Result<Box<Any>, EvalError>>>>, name: &str) -> Result<Box<Any>, EvalError> {
|
||||||
match self.fns_arity_0.get(name) {
|
match fns_arity_0.get(name) {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
for f in vf {
|
for f in vf {
|
||||||
let invoke = f();
|
let invoke = f();
|
||||||
@ -114,8 +114,10 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_fn_1_arg(&self, name: &str, arg1: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
|
pub fn call_fn_1_arg(fns_arity_1: &HashMap<String, Vec<Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
match self.fns_arity_1.get(name) {
|
name: &str, arg1: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
|
||||||
|
|
||||||
|
match fns_arity_1.get(name) {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
for f in vf {
|
for f in vf {
|
||||||
let invoke = f(arg1);
|
let invoke = f(arg1);
|
||||||
@ -130,8 +132,10 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_fn_2_arg(&self, name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
|
pub fn call_fn_2_arg(fns_arity_2: &HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
match self.fns_arity_2.get(name) {
|
name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
|
||||||
|
|
||||||
|
match fns_arity_2.get(name) {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
for f in vf {
|
for f in vf {
|
||||||
let invoke = f(arg1, arg2);
|
let invoke = f(arg1, arg2);
|
||||||
@ -146,6 +150,24 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call_fn_3_arg(fns_arity_3: &HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
|
||||||
|
name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>, arg3: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
|
||||||
|
|
||||||
|
match fns_arity_3.get(name) {
|
||||||
|
Some(vf) => {
|
||||||
|
for f in vf {
|
||||||
|
let invoke = f(arg1, arg2, arg3);
|
||||||
|
match invoke {
|
||||||
|
Ok(v) => return Ok(v),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Err(EvalError::FunctionArgMismatch)
|
||||||
|
}
|
||||||
|
None => Err(EvalError::FunctionNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn register_type<T: Clone+Any>(&mut self) {
|
fn register_type<T: Clone+Any>(&mut self) {
|
||||||
fn clone_helper<T: Clone>(t:T)->T { t.clone() };
|
fn clone_helper<T: Clone>(t:T)->T { t.clone() };
|
||||||
|
|
||||||
@ -196,20 +218,61 @@ impl Engine {
|
|||||||
_ => Err(EvalError::VariableNotFound)
|
_ => Err(EvalError::VariableNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(ref fn_name, ref args) => {
|
Expr::FnCall(ref fn_name, ref args) => {
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
self.call_fn_0_arg(&fn_name)
|
Engine::call_fn_0_arg(&self.fns_arity_0, &fn_name)
|
||||||
}
|
}
|
||||||
else if args.len() == 1 {
|
else if args.len() == 1 {
|
||||||
let mut arg = try!(self.eval_expr(&args[0]));
|
let mut arg = try!(self.eval_expr(&args[0]));
|
||||||
|
|
||||||
self.call_fn_1_arg(&fn_name, &mut arg)
|
Engine::call_fn_1_arg(&self.fns_arity_1, &fn_name, &mut arg)
|
||||||
}
|
}
|
||||||
else if args.len() == 2 {
|
else if args.len() == 2 {
|
||||||
let mut arg1 = try!(self.eval_expr(&args[0]));
|
let mut arg1 = try!(self.eval_expr(&args[0]));
|
||||||
let mut arg2 = try!(self.eval_expr(&args[1]));
|
let mut arg2 = try!(self.eval_expr(&args[1]));
|
||||||
|
|
||||||
self.call_fn_2_arg(&fn_name, &mut arg1, &mut arg2)
|
Engine::call_fn_2_arg(&self.fns_arity_2, &fn_name, &mut arg1, &mut arg2)
|
||||||
|
}
|
||||||
|
else if args.len() == 3 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(&args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(&args[1]));
|
||||||
|
let mut arg3 = try!(self.eval_expr(&args[1]));
|
||||||
|
|
||||||
|
Engine::call_fn_3_arg(&self.fns_arity_3, &fn_name, &mut arg1, &mut arg2, &mut arg3)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(EvalError::FunctionCallNotSupported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::MethodCall(ref target, ref fn_name, ref args) => {
|
||||||
|
if args.len() == 0 {
|
||||||
|
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
|
||||||
|
if *target == *name {
|
||||||
|
return Engine::call_fn_1_arg(&self.fns_arity_1, &fn_name, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(EvalError::VariableNotFound)
|
||||||
|
}
|
||||||
|
else if args.len() == 1 {
|
||||||
|
let mut arg = try!(self.eval_expr(&args[0]));
|
||||||
|
|
||||||
|
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
|
||||||
|
if *target == *name {
|
||||||
|
return Engine::call_fn_2_arg(&self.fns_arity_2, &fn_name, val, &mut arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(EvalError::VariableNotFound)
|
||||||
|
}
|
||||||
|
else if args.len() == 2 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(&args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(&args[1]));
|
||||||
|
|
||||||
|
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
|
||||||
|
if *target == *name {
|
||||||
|
return Engine::call_fn_3_arg(&self.fns_arity_3, &fn_name, val, &mut arg1, &mut arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(EvalError::VariableNotFound)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Err(EvalError::FunctionCallNotSupported)
|
Err(EvalError::FunctionCallNotSupported)
|
||||||
@ -295,8 +358,19 @@ impl Engine {
|
|||||||
let tree = parse(&mut peekables);
|
let tree = parse(&mut peekables);
|
||||||
|
|
||||||
match tree {
|
match tree {
|
||||||
Ok(os) => {
|
Ok((ref os, ref fns)) => {
|
||||||
let mut x: Result<Box<Any>, EvalError> = Ok(Box::new(()));
|
let mut x: Result<Box<Any>, EvalError> = Ok(Box::new(()));
|
||||||
|
for f in fns {
|
||||||
|
if f.params.len() == 0 {
|
||||||
|
let local_f = f.clone();
|
||||||
|
let ent = self.fns_arity_0.entry(local_f.name).or_insert(Vec::new());
|
||||||
|
let wrapped : Box<Fn()->Result<Box<Any>, EvalError>> =
|
||||||
|
Box::new(move || { Ok(Box::new(0)) } );
|
||||||
|
//move || { self.eval_stmt(&local_f.body) }
|
||||||
|
(*ent).push(wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for o in os {
|
for o in os {
|
||||||
x = self.eval_stmt(&o)
|
x = self.eval_stmt(&o)
|
||||||
}
|
}
|
||||||
@ -342,8 +416,8 @@ impl Engine {
|
|||||||
reg_cmp!(engine, "<=", lte, i32, i64, u32, u64);
|
reg_cmp!(engine, "<=", lte, i32, i64, u32, u64);
|
||||||
reg_cmp!(engine, ">", gt, i32, i64, u32, u64);
|
reg_cmp!(engine, ">", gt, i32, i64, u32, u64);
|
||||||
reg_cmp!(engine, ">=", gte, i32, i64, u32, u64);
|
reg_cmp!(engine, ">=", gte, i32, i64, u32, u64);
|
||||||
reg_cmp!(engine, "==", eq, i32, i64, u32, u64);
|
reg_cmp!(engine, "==", eq, i32, i64, u32, u64, bool);
|
||||||
reg_cmp!(engine, "!=", ne, i32, i64, u32, u64);
|
reg_cmp!(engine, "!=", ne, i32, i64, u32, u64, bool);
|
||||||
|
|
||||||
reg_op!(engine, "||", or, bool);
|
reg_op!(engine, "||", or, bool);
|
||||||
reg_op!(engine, "&&", and, bool);
|
reg_op!(engine, "&&", and, bool);
|
||||||
@ -354,6 +428,7 @@ impl Engine {
|
|||||||
fns_arity_0: HashMap::new(),
|
fns_arity_0: HashMap::new(),
|
||||||
fns_arity_1: HashMap::new(),
|
fns_arity_1: HashMap::new(),
|
||||||
fns_arity_2: HashMap::new(),
|
fns_arity_2: HashMap::new(),
|
||||||
|
fns_arity_3: HashMap::new(),
|
||||||
scope: Vec::new()
|
scope: Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -463,4 +538,35 @@ fn test_var_scope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_method_call() {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TestStruct {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestStruct {
|
||||||
|
fn update(&mut self) {
|
||||||
|
self.x += 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> TestStruct {
|
||||||
|
TestStruct { x: 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine.register_type::<TestStruct>();
|
||||||
|
|
||||||
|
&(TestStruct::update as fn(&mut TestStruct)->()).register(&mut engine, "update");
|
||||||
|
&(TestStruct::new as fn()->TestStruct).register(&mut engine, "new_ts");
|
||||||
|
|
||||||
|
if let Ok(result) = engine.eval("var x = new_ts(); x.update(); x".to_string()).unwrap().downcast::<TestStruct>() {
|
||||||
|
assert_eq!(result.x, 1001);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -7,6 +7,48 @@ pub trait FnRegister {
|
|||||||
fn register(self, engine: &mut Engine, name: &str);
|
fn register(self, engine: &mut Engine, name: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone, W: Any+Clone> FnRegister for fn(&mut T, U, V)->W {
|
||||||
|
fn register(self, engine: &mut Engine, name: &str) {
|
||||||
|
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
|
||||||
|
Box::new(
|
||||||
|
move |x: &mut Box<Any>, y: &mut Box<Any>, z: &mut Box<Any>| {
|
||||||
|
let inside1 = (*x).downcast_mut() as Option<&mut T>;
|
||||||
|
let inside2 = (*y).downcast_mut() as Option<&mut U>;
|
||||||
|
let inside3 = (*z).downcast_mut() as Option<&mut V>;
|
||||||
|
|
||||||
|
match (inside1, inside2, inside3) {
|
||||||
|
(Some(b), Some(c), Some(d)) => Ok(Box::new(self(b, c.clone(), d.clone())) as Box<Any>),
|
||||||
|
_ => Err(EvalError::FunctionArgMismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let ent = engine.fns_arity_3.entry(name.to_string()).or_insert(Vec::new());
|
||||||
|
(*ent).push(wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone, W: Any+Clone> FnRegister for fn(T, U, V)->W {
|
||||||
|
fn register(self, engine: &mut Engine, name: &str) {
|
||||||
|
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
|
||||||
|
Box::new(
|
||||||
|
move |x: &mut Box<Any>, y: &mut Box<Any>, z: &mut Box<Any>| {
|
||||||
|
let inside1 = (*x).downcast_mut() as Option<&mut T>;
|
||||||
|
let inside2 = (*y).downcast_mut() as Option<&mut U>;
|
||||||
|
let inside3 = (*z).downcast_mut() as Option<&mut V>;
|
||||||
|
|
||||||
|
match (inside1, inside2, inside3) {
|
||||||
|
(Some(b), Some(c), Some(d)) => Ok(Box::new(self(b.clone(), c.clone(), d.clone())) as Box<Any>),
|
||||||
|
_ => Err(EvalError::FunctionArgMismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let ent = engine.fns_arity_3.entry(name.to_string()).or_insert(Vec::new());
|
||||||
|
(*ent).push(wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone> FnRegister for fn(&mut T, U)->V {
|
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone> FnRegister for fn(&mut T, U)->V {
|
||||||
fn register(self, engine: &mut Engine, name: &str) {
|
fn register(self, engine: &mut Engine, name: &str) {
|
||||||
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
|
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
|
||||||
|
73
src/main.rs
73
src/main.rs
@ -14,78 +14,9 @@ mod parser;
|
|||||||
// Todo (in no particular order):
|
// Todo (in no particular order):
|
||||||
// * Function in script
|
// * Function in script
|
||||||
// * Doc some examples
|
// * Doc some examples
|
||||||
// * Refactor identifer to not require inlining of clone lookup in engine
|
// * String constants
|
||||||
// * Remove empty box values?
|
// * Remove empty box values?
|
||||||
// * Methods
|
// * Refactor identifer to not require inlining of clone lookup in engine?
|
||||||
|
|
||||||
/*
|
|
||||||
fn simple_fn(x: i32) -> bool { x == 1 }
|
|
||||||
fn simple_fn2(x: &mut i32) -> bool { x.clone() == 2 }
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestStruct {
|
|
||||||
x: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestStruct {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.x += 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new() -> TestStruct {
|
|
||||||
TestStruct { x: 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestStruct2 {
|
|
||||||
x: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestStruct2 {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.x = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn engine_test() {
|
|
||||||
let mut engine = Engine::new();
|
|
||||||
|
|
||||||
&(simple_fn as fn(i32)->bool).register(&mut engine, "simple_fn");
|
|
||||||
&(simple_fn2 as fn(&mut i32)->bool).register(&mut engine, "simple_fn2");
|
|
||||||
&(TestStruct::update as fn(&mut TestStruct)->()).register(&mut engine, "update");
|
|
||||||
&(TestStruct::new as fn()->TestStruct).register(&mut engine, "newteststruct");
|
|
||||||
&(showit as fn(x: &mut Box<Debug>)->()).register(&mut engine, "showit");
|
|
||||||
&(TestStruct2::update as fn(&mut TestStruct2)->()).register(&mut engine, "update");
|
|
||||||
|
|
||||||
let mut arg : Box<Any> = Box::new(2);
|
|
||||||
|
|
||||||
println!("Result: {:?}", engine.call_fn_1_arg("simple_fn" , &mut arg).unwrap().downcast::<bool>());
|
|
||||||
println!("Result: {:?}", engine.call_fn_1_arg("simple_fn2", &mut arg).unwrap().downcast::<bool>());
|
|
||||||
println!("Intentional errors: ");
|
|
||||||
println!(" Result: {:?}", engine.call_fn_1_arg("simple_fn3", &mut arg));
|
|
||||||
arg = Box::new("foo");
|
|
||||||
println!(" Result: {:?}", engine.call_fn_1_arg("simple_fn", &mut arg));
|
|
||||||
|
|
||||||
let mut ts : Box<Any> = Box::new(TestStruct { x: 6 });
|
|
||||||
engine.call_fn_1_arg("update" , &mut ts);
|
|
||||||
|
|
||||||
let result : Result<Box<TestStruct>, Box<Any>> = ts.downcast();
|
|
||||||
println!("TS: {:?}", result);
|
|
||||||
|
|
||||||
let myts = engine.call_fn_0_arg("newteststruct").unwrap().downcast::<TestStruct>();
|
|
||||||
println!("MyTS: {:?}", myts);
|
|
||||||
|
|
||||||
let mut mybox = Box::new(Box::new(56) as Box<Debug>) as Box<Any>;
|
|
||||||
engine.call_fn_1_arg("showit", &mut mybox);
|
|
||||||
|
|
||||||
let mut ts2 : Box<Any> = Box::new(TestStruct2 { x: false });
|
|
||||||
engine.call_fn_1_arg("update" , &mut ts2);
|
|
||||||
|
|
||||||
let result2 : Result<Box<TestStruct2>, Box<Any>> = ts2.downcast();
|
|
||||||
println!("TS2: {:?}", result2);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn showit<T: Display>(x: &mut T) -> () {
|
fn showit<T: Display>(x: &mut T) -> () {
|
||||||
println!("{}", x)
|
println!("{}", x)
|
||||||
|
174
src/parser.rs
174
src/parser.rs
@ -13,7 +13,10 @@ pub enum ParseError {
|
|||||||
MissingLCurly,
|
MissingLCurly,
|
||||||
MissingRCurly,
|
MissingRCurly,
|
||||||
MalformedCallExpr,
|
MalformedCallExpr,
|
||||||
VarExpectsIdentifier
|
VarExpectsIdentifier,
|
||||||
|
ExpectedMethodInvocation,
|
||||||
|
FnMissingName,
|
||||||
|
FnMissingParams
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for ParseError {
|
impl Error for ParseError {
|
||||||
@ -26,7 +29,10 @@ impl Error for ParseError {
|
|||||||
ParseError::MissingLCurly => "Expected '{'",
|
ParseError::MissingLCurly => "Expected '{'",
|
||||||
ParseError::MissingRCurly => "Expected '}'",
|
ParseError::MissingRCurly => "Expected '}'",
|
||||||
ParseError::MalformedCallExpr => "Call contains bad expression",
|
ParseError::MalformedCallExpr => "Call contains bad expression",
|
||||||
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable"
|
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
|
||||||
|
ParseError::ExpectedMethodInvocation => "Expected method call after '.'",
|
||||||
|
ParseError::FnMissingName => "Function declaration is missing name",
|
||||||
|
ParseError::FnMissingParams => "Function declaration is missing parameters"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,17 +47,25 @@ impl fmt::Display for ParseError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FnDef {
|
||||||
|
pub name: String,
|
||||||
|
pub params: Vec<String>,
|
||||||
|
pub body: Box<Stmt>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum Stmt { If(Box<Expr>, Box<Stmt>), While(Box<Expr>, Box<Stmt>), Var(String, Option<Box<Expr>>),
|
pub enum Stmt { If(Box<Expr>, Box<Stmt>), While(Box<Expr>, Box<Stmt>), Var(String, Option<Box<Expr>>),
|
||||||
Block(Box<Vec<Stmt>>), Expr(Box<Expr>) }
|
Block(Box<Vec<Stmt>>), Expr(Box<Expr>) }
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr { IntConst(i32), Identifier(String), Call(String, Box<Vec<Expr>>), Assignment(Box<Expr>, Box<Expr>), True, False }
|
pub enum Expr { IntConst(i32), Identifier(String), FnCall(String, Box<Vec<Expr>>), MethodCall(String, String, Box<Vec<Expr>>),
|
||||||
|
Assignment(Box<Expr>, Box<Expr>), True, False }
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Token { Int(i32), Id(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
|
pub enum Token { Int(i32), Id(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
|
||||||
Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Equals, True, False, Var, If, While,
|
Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Period, Equals, True, False, Var, If, While,
|
||||||
LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And }
|
LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And, Fn }
|
||||||
|
|
||||||
pub struct TokenIterator<'a> {
|
pub struct TokenIterator<'a> {
|
||||||
char_stream: Peekable<Chars<'a>>
|
char_stream: Peekable<Chars<'a>>
|
||||||
@ -110,6 +124,9 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
else if out == "while" {
|
else if out == "while" {
|
||||||
return Some(Token::While);
|
return Some(Token::While);
|
||||||
}
|
}
|
||||||
|
else if out == "fn" {
|
||||||
|
return Some(Token::Fn);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return Some(Token::Id(out));
|
return Some(Token::Id(out));
|
||||||
}
|
}
|
||||||
@ -127,6 +144,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
';' => { return Some(Token::Semicolon); },
|
';' => { return Some(Token::Semicolon); },
|
||||||
':' => { return Some(Token::Colon); },
|
':' => { return Some(Token::Colon); },
|
||||||
',' => { return Some(Token::Comma); },
|
',' => { return Some(Token::Comma); },
|
||||||
|
'.' => { return Some(Token::Period); },
|
||||||
'=' => {
|
'=' => {
|
||||||
match self.char_stream.peek() {
|
match self.char_stream.peek() {
|
||||||
Some(&'=') => {self.char_stream.next(); return Some(Token::EqualTo); },
|
Some(&'=') => {self.char_stream.next(); return Some(Token::EqualTo); },
|
||||||
@ -204,17 +222,35 @@ fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
||||||
|
let id2 = match input.peek() {
|
||||||
|
Some(&Token::Period) => {
|
||||||
|
input.next();
|
||||||
|
match input.next() {
|
||||||
|
Some(Token::Id(ref s)) => {
|
||||||
|
s.clone()
|
||||||
|
}
|
||||||
|
_ => return Err(ParseError::ExpectedMethodInvocation)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => String::new()
|
||||||
|
};
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::LParen) => (),
|
Some(&Token::LParen) => {input.next();},
|
||||||
_ => return Ok(Expr::Identifier(id))
|
_ => return Ok(Expr::Identifier(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
input.next();
|
|
||||||
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::RParen) => {input.next(); return Ok(Expr::Call(id, Box::new(args)))},
|
Some(&Token::RParen) => {
|
||||||
|
input.next();
|
||||||
|
if id2 == "" {
|
||||||
|
return Ok(Expr::FnCall(id, Box::new(args)))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +263,15 @@ fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::RParen) => {input.next(); return Ok(Expr::Call(id, Box::new(args)))},
|
Some(&Token::RParen) => {
|
||||||
|
input.next();
|
||||||
|
if id2 == "" {
|
||||||
|
return Ok(Expr::FnCall(id, Box::new(args)))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(&Token::Comma) => (),
|
Some(&Token::Comma) => (),
|
||||||
_ => return Err(ParseError::MalformedCallExpr)
|
_ => return Err(ParseError::MalformedCallExpr)
|
||||||
}
|
}
|
||||||
@ -280,19 +324,19 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>, prec: i32, lhs: Expr
|
|||||||
}
|
}
|
||||||
|
|
||||||
lhs_curr = match op_token {
|
lhs_curr = match op_token {
|
||||||
Token::Plus => Expr::Call("+".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Plus => Expr::FnCall("+".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Minus => Expr::Call("-".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Minus => Expr::FnCall("-".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Multiply => Expr::Call("*".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Multiply => Expr::FnCall("*".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Divide => Expr::Call("/".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Divide => Expr::FnCall("/".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
||||||
Token::EqualTo => Expr::Call("==".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::EqualTo => Expr::FnCall("==".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::NotEqualTo => Expr::Call("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::NotEqualTo => Expr::FnCall("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::LessThan => Expr::Call("<".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::LessThan => Expr::FnCall("<".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::LessThanEqual => Expr::Call("<=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::LessThanEqual => Expr::FnCall("<=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::GreaterThan => Expr::Call(">".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::GreaterThan => Expr::FnCall(">".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::GreaterThanEqual => Expr::Call(">=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::GreaterThanEqual => Expr::FnCall(">=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Or => Expr::Call("||".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Or => Expr::FnCall("||".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::And => Expr::Call("&&".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::And => Expr::FnCall("&&".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
_ => return Err(ParseError::UnknownOperator)
|
_ => return Err(ParseError::UnknownOperator)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -349,7 +393,27 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
|
|||||||
|
|
||||||
input.next();
|
input.next();
|
||||||
|
|
||||||
let stmts = try!(parse_stmts(input, true));
|
let mut stmts = Vec::new();
|
||||||
|
|
||||||
|
let skip_body = match input.peek() {
|
||||||
|
Some(& Token::RCurly) => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !skip_body {
|
||||||
|
while let Some(_) = input.peek() {
|
||||||
|
stmts.push(try!(parse_stmt(input)));
|
||||||
|
match input.peek() {
|
||||||
|
Some(& Token::Semicolon) => {input.next();},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
match input.peek() {
|
||||||
|
Some(& Token::RCurly) => break,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(& Token::RCurly) => {input.next(); Ok(Stmt::Block(Box::new(stmts)))},
|
Some(& Token::RCurly) => {input.next(); Ok(Stmt::Block(Box::new(stmts)))},
|
||||||
@ -372,35 +436,61 @@ fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Parse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmts<'a>(input: &mut Peekable<TokenIterator<'a>>, check_for_rcurly: bool) -> Result<Vec<Stmt>, ParseError> {
|
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseError> {
|
||||||
let mut result = Vec::new();
|
input.next();
|
||||||
|
|
||||||
|
let name = match input.next() {
|
||||||
|
Some(Token::Id(ref s)) => s.clone(),
|
||||||
|
_ => return Err(ParseError::FnMissingName)
|
||||||
|
};
|
||||||
|
|
||||||
if check_for_rcurly {
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(& Token::RCurly) => return Ok(result),
|
Some(&Token::LParen) => {input.next();},
|
||||||
_ => ()
|
_ => return Err(ParseError::FnMissingParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut params = Vec::new();
|
||||||
|
|
||||||
|
let skip_params = match input.peek() {
|
||||||
|
Some(&Token::RParen) => { input.next(); true }
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !skip_params {
|
||||||
|
loop {
|
||||||
|
match input.next() {
|
||||||
|
Some(Token::RParen) => { break },
|
||||||
|
Some(Token::Comma) => (),
|
||||||
|
Some(Token::Id(ref s)) => { params.push(s.clone()); },
|
||||||
|
_ => return Err(ParseError::MalformedCallExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = try!(parse_block(input));
|
||||||
|
|
||||||
|
Ok(FnDef{name: name, params: params, body: Box::new(body)})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
|
||||||
|
let mut stmts = Vec::new();
|
||||||
|
let mut fndefs = Vec::new();
|
||||||
|
|
||||||
while let Some(_) = input.peek() {
|
while let Some(_) = input.peek() {
|
||||||
result.push(try!(parse_stmt(input)));
|
match input.peek() {
|
||||||
|
Some(& Token::Fn) => fndefs.push(try!(parse_fn(input))),
|
||||||
|
_ => stmts.push(try!(parse_stmt(input)))
|
||||||
|
}
|
||||||
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(& Token::Semicolon) => {input.next();},
|
Some(& Token::Semicolon) => {input.next();},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if check_for_rcurly {
|
|
||||||
match input.peek() {
|
|
||||||
Some(& Token::RCurly) => return Ok(result),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok((stmts, fndefs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Vec<Stmt>, ParseError> {
|
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
|
||||||
let result = parse_stmts(input, false);
|
parse_top_level(input)
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user