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

@@ -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::<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, _| {
let obj_ptr: ObjPtr = machine.stack_pop()?;
let obj: &(dyn Obj + 'static) = &*obj_ptr;

View File

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