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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user