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:
@@ -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
28
examples/factorial.sy
Normal 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!
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user