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 <alekratz@gmail.com>
This commit is contained in:
2022-02-11 11:10:14 -08:00
parent a8cf2898e1
commit 1f642b9739
4 changed files with 110 additions and 10 deletions

View File

@@ -1,7 +1,7 @@
[ "fail - 0 is not truthy" println! ] [ "OK" println! ] 0 if! 0 [ "fail - 0 is not truthy" println! ] [ "OK" println! ] if!
[ "OK" println! ] [ "fail - 1 is truthy" println! ] 1 if! 1 [ "OK" println! ] [ "fail - 1 is truthy" println! ] if!
[ "OK" println! ] [ "fail - 1.1 is truthy" println! ] 1.1 if! 1.1 [ "OK" println! ] [ "fail - 1.1 is truthy" println! ] if!
[ "OK" println! ] [ "fail - 0.1 is truthy" println! ] 0.1 if! 0.1 [ "OK" println! ] [ "fail - 0.1 is truthy" println! ] if!
[ "OK" println! ] [ "fail - -0.1 is truthy" println! ] -0.1 if! -0.1 [ "OK" println! ] [ "fail - -0.1 is truthy" println! ] if!
[ "fail - -0.0 is not truthy" println! ] [ "OK" println! ] -0.0 if! -0.0 [ "fail - -0.0 is not truthy" println! ] [ "OK" println! ] if!
[ "fail - 0.0 is not truthy" println! ] [ "OK" println! ] 0.0 if! 0.0 [ "fail - 0.0 is not truthy" println! ] [ "OK" println! ] if!

28
examples/factorial.sy Normal file
View File

@@ -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!

View File

@@ -49,6 +49,26 @@ thread_local! {
(None, None) => { panic!("called an int builtin with no int values at all"); } (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::<IntObj>();
let rhs = rhs_ptr.as_any().downcast_ref::<IntObj>();
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, _| { .with_builtin("__bool__", |machine, _| {
let obj_ptr: ObjPtr = machine.stack_pop()?; let obj_ptr: ObjPtr = machine.stack_pop()?;
let obj: &(dyn Obj + 'static) = &*obj_ptr; let obj: &(dyn Obj + 'static) = &*obj_ptr;

View File

@@ -35,22 +35,28 @@ impl MachineBuilder {
// //
// if // if
// (condition if_true if_false -- ?)
// //
self.register_builtin_fun("if", |machine, reentry| { self.register_builtin_fun("if", |machine, reentry| {
const CALL_BOOL: usize = 1; const CALL_BOOL: usize = 1;
const RETURN: usize = 2; const RETURN: usize = 2;
if reentry == 0 { 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 // get __bool__ attr from condition stack member
let bool_fun = machine let bool_fun = condition
.stack_peek()
.ok_or_else(|| RuntimeError::StackUnderflow)?
.get("__bool__") .get("__bool__")
.ok_or_else(|| RuntimeError::UnsetWord("__bool__".to_string()))?; .ok_or_else(|| RuntimeError::UnsetWord("__bool__".to_string()))?;
// call it // call it
let call_site = machine.call_stack().last().unwrap().call_site().cloned(); let call_site = machine.call_stack().last().unwrap().call_site().cloned();
bool_fun.call(call_site, machine)?; 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)) Ok(BuiltinExit::Resume(CALL_BOOL))
} else if reentry == CALL_BOOL { } else if reentry == CALL_BOOL {
let obj_ptr = machine.stack_pop()?; 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 // print
// //