From 1f642b9739eb7a85734033fc35c8911a4de36191 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Fri, 11 Feb 2022 11:10:14 -0800 Subject: [PATCH] Change `if` function stack ordering, add some basic math ops to Int, add factorial example * `if` function stack ordering is changed to use condition, if-false, if-true (bottom to top). This is so we can pass a value on top of the stack directly to a new `if` in a condition, so we don't have to store a new value in a new variable. * Add __splat__ and __minus__ functions to Int * Add * and - builtins, which call the __splat__ and __minus__ functions of the top stack item, respectively. * Add factorial example because now factorials are possible with this skeleton implementation, albeit a little hacky with the recursion. Signed-off-by: Alek Ratzloff --- examples/branch.sy | 14 +++++------ examples/factorial.sy | 28 +++++++++++++++++++++ src/obj/int.rs | 20 +++++++++++++++ src/vm/builtins.rs | 58 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 examples/factorial.sy diff --git a/examples/branch.sy b/examples/branch.sy index baf6a03..d00dfec 100644 --- a/examples/branch.sy +++ b/examples/branch.sy @@ -1,7 +1,7 @@ -[ "fail - 0 is not truthy" println! ] [ "OK" println! ] 0 if! -[ "OK" println! ] [ "fail - 1 is truthy" println! ] 1 if! -[ "OK" println! ] [ "fail - 1.1 is truthy" println! ] 1.1 if! -[ "OK" println! ] [ "fail - 0.1 is truthy" println! ] 0.1 if! -[ "OK" println! ] [ "fail - -0.1 is truthy" println! ] -0.1 if! -[ "fail - -0.0 is not truthy" println! ] [ "OK" println! ] -0.0 if! -[ "fail - 0.0 is not truthy" println! ] [ "OK" println! ] 0.0 if! \ No newline at end of file +0 [ "fail - 0 is not truthy" println! ] [ "OK" println! ] if! +1 [ "OK" println! ] [ "fail - 1 is truthy" println! ] if! +1.1 [ "OK" println! ] [ "fail - 1.1 is truthy" println! ] if! +0.1 [ "OK" println! ] [ "fail - 0.1 is truthy" println! ] if! +-0.1 [ "OK" println! ] [ "fail - -0.1 is truthy" println! ] if! +-0.0 [ "fail - -0.0 is not truthy" println! ] [ "OK" println! ] if! +0.0 [ "fail - 0.0 is not truthy" println! ] [ "OK" println! ] if! \ No newline at end of file diff --git a/examples/factorial.sy b/examples/factorial.sy new file mode 100644 index 0000000..0a6048d --- /dev/null +++ b/examples/factorial.sy @@ -0,0 +1,28 @@ +[ :x x x ] :dup + +0 :factorial +[ + dup! + [dup! 1 -! factorial! *!] + [:_ 1] + if! +] +:factorial + +[ + dup! print! + "! = " print! + factorial! + println! +] +:do-factorial + +1 do-factorial! +2 do-factorial! +3 do-factorial! +4 do-factorial! +5 do-factorial! +6 do-factorial! +7 do-factorial! +8 do-factorial! +9 do-factorial! \ No newline at end of file diff --git a/src/obj/int.rs b/src/obj/int.rs index 029dc5f..d8d1b7f 100644 --- a/src/obj/int.rs +++ b/src/obj/int.rs @@ -49,6 +49,26 @@ thread_local! { (None, None) => { panic!("called an int builtin with no int values at all"); } } }) + .with_builtin("__minus__", |machine, _| { + let rhs_ptr: ObjPtr = machine.stack_pop()?; + let lhs_ptr: ObjPtr = machine.stack_pop()?; + let lhs = lhs_ptr.as_any().downcast_ref::(); + let rhs = rhs_ptr.as_any().downcast_ref::(); + match (lhs, rhs) { + (Some(lhs), Some(rhs)) => { + let result = IntObj::new(lhs.value() - rhs.value()); + machine.stack_push(result)?; + Ok(BuiltinExit::Return) + } + (Some(_lhs), None) => { + Err(RuntimeError::WrongValue("int value (rhs)".to_string())) + }, + (None, Some(_rhs)) => { + Err(RuntimeError::WrongValue("int value (lhs)".to_string())) + } + (None, None) => { panic!("called an int builtin with no int values at all"); } + } + }) .with_builtin("__bool__", |machine, _| { let obj_ptr: ObjPtr = machine.stack_pop()?; let obj: &(dyn Obj + 'static) = &*obj_ptr; diff --git a/src/vm/builtins.rs b/src/vm/builtins.rs index 4e4f8a5..b9b6e32 100644 --- a/src/vm/builtins.rs +++ b/src/vm/builtins.rs @@ -35,22 +35,28 @@ impl MachineBuilder { // // if + // (condition if_true if_false -- ?) // self.register_builtin_fun("if", |machine, reentry| { const CALL_BOOL: usize = 1; const RETURN: usize = 2; if reentry == 0 { + let if_false = machine.stack_pop()?; + let if_true = machine.stack_pop()?; + let condition = machine.stack_pop()?; + // get __bool__ attr from condition stack member - let bool_fun = machine - .stack_peek() - .ok_or_else(|| RuntimeError::StackUnderflow)? + let bool_fun = condition .get("__bool__") .ok_or_else(|| RuntimeError::UnsetWord("__bool__".to_string()))?; // call it let call_site = machine.call_stack().last().unwrap().call_site().cloned(); bool_fun.call(call_site, machine)?; + machine.stack_push(if_true)?; + machine.stack_push(if_false)?; + machine.stack_push(condition)?; Ok(BuiltinExit::Resume(CALL_BOOL)) } else if reentry == CALL_BOOL { let obj_ptr = machine.stack_pop()?; @@ -78,6 +84,52 @@ impl MachineBuilder { } }); + // + // splat op + // + self.register_builtin_fun("*", |machine, reentry| { + const CALL_SPLAT: usize = 1; + if reentry == 0 { + let obj = machine + .stack_peek() + .ok_or_else(|| RuntimeError::StackUnderflow)?; + // Push the value's __str__ value, call it, and then print it. + let splat_fun = obj + .get("__splat__") + .ok_or_else(|| RuntimeError::UnsetWord("__splat__".to_string()))?; + let call_site = machine.call_stack().last().unwrap().call_site().cloned(); + splat_fun.call(call_site, machine)?; + Ok(BuiltinExit::Resume(CALL_SPLAT)) + } else if reentry == CALL_SPLAT { + Ok(BuiltinExit::Return) + } else { + unreachable!() + } + }); + + // + // minus op + // + self.register_builtin_fun("-", |machine, reentry| { + const CALL_MINUS: usize = 1; + if reentry == 0 { + let obj = machine + .stack_peek() + .ok_or_else(|| RuntimeError::StackUnderflow)?; + // Push the value's __str__ value, call it, and then print it. + let minus_fun = obj + .get("__minus__") + .ok_or_else(|| RuntimeError::UnsetWord("__minus__".to_string()))?; + let call_site = machine.call_stack().last().unwrap().call_site().cloned(); + minus_fun.call(call_site, machine)?; + Ok(BuiltinExit::Resume(CALL_MINUS)) + } else if reentry == CALL_MINUS { + Ok(BuiltinExit::Return) + } else { + unreachable!() + } + }); + // // print //