From c6212f5597646da4308574eb68d3c7587dc6e926 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Mon, 9 Nov 2020 16:50:16 -0800 Subject: [PATCH] Finish up old example that shows off basic expressions and funcalls The VM now supports the various int comparison methods. An example of a "pow" method is given to show off recursion, which means we're now TURING COMPLETE! Signed-off-by: Alek Ratzloff --- examples/expr.not | 20 +++++++----- src/obj/int.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++ src/obj/mod.rs | 4 +-- src/obj/reserved.rs | 12 ++----- src/vm/mod.rs | 77 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 165 insertions(+), 28 deletions(-) diff --git a/examples/expr.not b/examples/expr.not index 84621e0..c6cc61c 100644 --- a/examples/expr.not +++ b/examples/expr.not @@ -1,13 +1,15 @@ -# pow = fn (n, p) { -# if p == 0 { -# 1 -# } else { -# n * pow(n, p - 1) -# } -# } +pow = fn (n, p) { + if p <= 0 { + return 1 + } el { + return n * pow(n, p - 1) + } +} kilo = pow(2, 10) mega = pow(2, 20) giga = pow(2, 30) -tera = pow(2, 40) -peta = pow(2, 50) + +println(kilo) +println(mega) +println(giga) diff --git a/src/obj/int.rs b/src/obj/int.rs index 5a29d92..87cfc2c 100644 --- a/src/obj/int.rs +++ b/src/obj/int.rs @@ -36,6 +36,10 @@ impl Int { DIV_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_DIV_METH.clone()), EQ_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_EQ_METH.clone()), NE_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_NE_METH.clone()), + LT_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_LT_METH.clone()), + LE_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_LE_METH.clone()), + GT_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_GT_METH.clone()), + GE_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_GE_METH.clone()), } } } @@ -210,3 +214,79 @@ static INT_NE_METH: Lazy = Lazy::new(|| { Ok(crate::vm::signal::Signal::Return) }) }); + +/// Int.__lt__(self, Int) impl +static INT_LT_METH: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let result = lhs.value < rhs.value; + vm.push(BoolRef::from(result)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__le__(self, Int) impl +static INT_LE_METH: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let result = lhs.value <= rhs.value; + vm.push(BoolRef::from(result)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__gt__(self, Int) impl +static INT_GT_METH: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let result = lhs.value > rhs.value; + vm.push(BoolRef::from(result)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__ge__(self, Int) impl +static INT_GE_METH: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let result = lhs.value >= rhs.value; + vm.push(BoolRef::from(result)); + Ok(crate::vm::signal::Signal::Return) + }) +}); diff --git a/src/obj/mod.rs b/src/obj/mod.rs index fc12b18..16a806e 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -72,8 +72,8 @@ pub trait Obj: Scan + GcDrop + Debug { obj_attr!(get_ne, NE_OP_NAME); obj_attr!(get_lt, LT_OP_NAME); obj_attr!(get_gt, GT_OP_NAME); - obj_attr!(get_le, LT_EQ_OP_NAME); - obj_attr!(get_ge, GT_EQ_OP_NAME); + obj_attr!(get_le, LE_OP_NAME); + obj_attr!(get_ge, GE_OP_NAME); obj_attr!(get_plus, PLUS_OP_NAME); obj_attr!(get_minus, MINUS_OP_NAME); obj_attr!(get_mul, TIMES_OP_NAME); diff --git a/src/obj/reserved.rs b/src/obj/reserved.rs index 04c3b4a..80c1bc3 100644 --- a/src/obj/reserved.rs +++ b/src/obj/reserved.rs @@ -48,17 +48,9 @@ name!(STR_MEMBER_NAME, "__str__"); name!(INT_MEMBER_NAME, "__int__"); name!(BOOL_MEMBER_NAME, "__bool__"); -// -// Predefined VM-aware symbols -// -//name!(SCOPE_NAME, "__scope__"); - // // Builtin functions // -//name!(REPR_FUN_NAME, REPR_FUN_SYM, "repr"); -//name!(GET_LOCAL_FUN_NAME, GET_LOCAL_FUN_SYM, "get_local"); -//name!(SET_LOCAL_FUN_NAME, SET_LOCAL_FUN_SYM, "set_local"); name!(PRINTLN_BUILTIN_NAME, "println"); name!(PRINT_BUILTIN_NAME, "print"); @@ -71,9 +63,9 @@ name!(NIL_NAME, "nil"); name!(EQ_OP_NAME, "__eq__"); name!(NE_OP_NAME, "__ne__"); name!(LT_OP_NAME, "__lt__"); +name!(LE_OP_NAME, "__le__"); name!(GT_OP_NAME, "__gt__"); -name!(LT_EQ_OP_NAME, "__le__"); -name!(GT_EQ_OP_NAME, "__ge__"); +name!(GE_OP_NAME, "__ge__"); name!(PLUS_OP_NAME, "__add__"); name!(MINUS_OP_NAME, "__sub__"); name!(TIMES_OP_NAME, "__mul__"); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 10dea60..f742f01 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -337,13 +337,76 @@ impl<'c> Vm<'c> { }; signal = Some(Signal::Call(fun, vec![rhs])); } - Inst::BinNeq => todo!(), - Inst::BinLt => todo!(), - Inst::BinLe => todo!(), - Inst::BinGt => todo!(), - Inst::BinGe => todo!(), - Inst::BinAnd => todo!(), - Inst::BinOr => todo!(), + Inst::BinNeq => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_ne() + .expect("TODO: throw an error for missing __ne__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinLt => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_lt() + .expect("TODO: throw an error for missing __lt__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinLe => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_le() + .expect("TODO: throw an error for missing __le__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinGt => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_gt() + .expect("TODO: throw an error for missing __gt__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinGe => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_ge() + .expect("TODO: throw an error for missing __ge__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinAnd => todo!(), /*{ + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_and() + .expect("TODO: throw an error for missing __and__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + }*/ + Inst::BinOr => todo!(), /*{ + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_or() + .expect("TODO: throw an error for missing __or__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); + }*/ } self.set_pc(next_pc);