Add do_call macro, implement Bool builtins, add tests
* I noticed that `fn call(...)` in all objects was identical, so I made a macro for it. This should make things a little easier to read, since do_call is about 30 lines a pop. * Bool has a constructor now, and a to_int and to_float implementations * Add tests for constructors and add new bool tests Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
133
src/builtins.rs
133
src/builtins.rs
@@ -33,6 +33,39 @@ pub fn init_global_builtins() {
|
|||||||
//
|
//
|
||||||
// This would probably be doable in a procedural macro.
|
// This would probably be doable in a procedural macro.
|
||||||
|
|
||||||
|
macro_rules! impl_do_call {
|
||||||
|
($name:ident) => {
|
||||||
|
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||||
|
match state {
|
||||||
|
FunctionState::Begin => {
|
||||||
|
// get the top item off the stack and call to_float on it
|
||||||
|
let arg = vm.peek();
|
||||||
|
let method = if let Some(method) =
|
||||||
|
arg.borrow().get_vtable_attr(arg.clone(), stringify!($name))
|
||||||
|
{
|
||||||
|
method
|
||||||
|
} else {
|
||||||
|
// TODO builtins::do_call - throw exception when target doesn't have a
|
||||||
|
// to_$name method
|
||||||
|
// BLOCKED-ON: exceptions
|
||||||
|
todo!(
|
||||||
|
concat!("{} does not have a ", stringify!($name), " method"),
|
||||||
|
arg.borrow().ty_name()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
vm.push(method.clone());
|
||||||
|
method.borrow().call(vm, 0);
|
||||||
|
|
||||||
|
// resume execution
|
||||||
|
FunctionResult::Yield(0)
|
||||||
|
}
|
||||||
|
FunctionState::Resume(0) => FunctionResult::Return,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Global functions
|
// Global functions
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -211,31 +244,7 @@ impl BaseObj {
|
|||||||
// Str implementations
|
// Str implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
impl Str {
|
impl Str {
|
||||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
impl_do_call!(to_str);
|
||||||
match state {
|
|
||||||
FunctionState::Begin => {
|
|
||||||
// get the top item off the stack and call to_str on it
|
|
||||||
let arg = vm.peek();
|
|
||||||
let method =
|
|
||||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_str") {
|
|
||||||
method
|
|
||||||
} else {
|
|
||||||
// TODO Str::do_call - throw exception when target doesn't have a to_str()
|
|
||||||
// method
|
|
||||||
// BLOCKED-ON: exceptions
|
|
||||||
todo!("{} does not have a to_str() method", arg.borrow().ty_name());
|
|
||||||
// NOTE - every object should have to_str, right?
|
|
||||||
};
|
|
||||||
vm.push(method.clone());
|
|
||||||
method.borrow().call(vm, 0);
|
|
||||||
|
|
||||||
// resume execution
|
|
||||||
FunctionResult::Yield(0)
|
|
||||||
}
|
|
||||||
FunctionState::Resume(0) => FunctionResult::Return,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||||
@@ -380,31 +389,7 @@ impl Int {
|
|||||||
Float::create(int_value as f64).into()
|
Float::create(int_value as f64).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
impl_do_call!(to_int);
|
||||||
match state {
|
|
||||||
FunctionState::Begin => {
|
|
||||||
// Pop the argument and call `to_int` on it
|
|
||||||
let arg = vm.peek();
|
|
||||||
|
|
||||||
let method =
|
|
||||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_int") {
|
|
||||||
method
|
|
||||||
} else {
|
|
||||||
// TODO Int::do_call - throw exception when arg doesn't have to_int()
|
|
||||||
// method
|
|
||||||
// BLOCKED-ON: exceptions
|
|
||||||
todo!("{} does not have a to_int() method", arg.borrow().ty_name());
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.push(method.clone());
|
|
||||||
method.borrow().call(vm, 0);
|
|
||||||
|
|
||||||
FunctionResult::Yield(0)
|
|
||||||
}
|
|
||||||
FunctionState::Resume(0) => FunctionResult::Return,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||||
@@ -522,33 +507,7 @@ macro_rules! float_bin_op_logical {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Float {
|
impl Float {
|
||||||
pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
impl_do_call!(to_float);
|
||||||
match state {
|
|
||||||
FunctionState::Begin => {
|
|
||||||
// get the top item off the stack and call to_float on it
|
|
||||||
let arg = vm.peek();
|
|
||||||
let method =
|
|
||||||
if let Some(method) = arg.borrow().get_vtable_attr(arg.clone(), "to_float") {
|
|
||||||
method
|
|
||||||
} else {
|
|
||||||
// TODO Float::do_call - throw exception when target doesn't have a to_float()
|
|
||||||
// method
|
|
||||||
// BLOCKED-ON: exceptions
|
|
||||||
todo!(
|
|
||||||
"{} does not have a to_float() method",
|
|
||||||
arg.borrow().ty_name()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
vm.push(method.clone());
|
|
||||||
method.borrow().call(vm, 0);
|
|
||||||
|
|
||||||
// resume execution
|
|
||||||
FunctionResult::Yield(0)
|
|
||||||
}
|
|
||||||
FunctionState::Resume(0) => FunctionResult::Return,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||||
@@ -590,3 +549,23 @@ impl Float {
|
|||||||
Float::create(-value).into()
|
Float::create(-value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Bool {
|
||||||
|
impl_do_call!(to_bool);
|
||||||
|
|
||||||
|
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
|
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||||
|
// instantiation is done in the `__call__` function.
|
||||||
|
FunctionResult::ReturnPush(Nil::create())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
|
let bool_value = with_obj_downcast(vm.frame_stack()[0].clone(), Bool::bool_value);
|
||||||
|
Int::create(bool_value as i64).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
|
let bool_value = with_obj_downcast(vm.frame_stack()[0].clone(), Bool::bool_value);
|
||||||
|
Float::create(bool_value as i64 as f64).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
12
src/obj.rs
12
src/obj.rs
@@ -210,7 +210,17 @@ pub fn init_types() {
|
|||||||
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
||||||
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
||||||
},
|
},
|
||||||
Bool { },
|
Bool {
|
||||||
|
// Conversion methods
|
||||||
|
to_int => BuiltinFunction::create("to_int", Bool::to_int, 1),
|
||||||
|
to_float => BuiltinFunction::create("to_float", Bool::to_float, 1),
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
__call__ => BuiltinFunction::create("__call__", Bool::do_call, 2),
|
||||||
|
__init__ => BuiltinFunction::create("__init__", Bool::init, 2),
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
},
|
||||||
Nil { },
|
Nil { },
|
||||||
BuiltinFunction { },
|
BuiltinFunction { },
|
||||||
UserFunction { },
|
UserFunction { },
|
||||||
|
|||||||
72
tests/bool.npp
Normal file
72
tests/bool.npp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Bool type operator and function tests
|
||||||
|
|
||||||
|
a = true
|
||||||
|
b = false
|
||||||
|
|
||||||
|
# __not__
|
||||||
|
println("__not__")
|
||||||
|
println(!a)
|
||||||
|
println(!!a)
|
||||||
|
println(!!!a)
|
||||||
|
println(!!!!a)
|
||||||
|
println(!b)
|
||||||
|
println(!!b)
|
||||||
|
println(!!!b)
|
||||||
|
println(!!!!b)
|
||||||
|
|
||||||
|
# __and__
|
||||||
|
println("__and__")
|
||||||
|
println(a && b)
|
||||||
|
println(b && a)
|
||||||
|
println(a && a)
|
||||||
|
println(b && b)
|
||||||
|
|
||||||
|
# __or__
|
||||||
|
println("__or__")
|
||||||
|
println(a || b)
|
||||||
|
println(b || a)
|
||||||
|
println(a || a)
|
||||||
|
println(b || b)
|
||||||
|
|
||||||
|
# __eq__
|
||||||
|
println("__eq__")
|
||||||
|
println(a == a)
|
||||||
|
println(a == b)
|
||||||
|
println(b == b)
|
||||||
|
println(b == a)
|
||||||
|
println(a == true)
|
||||||
|
println(true == a)
|
||||||
|
println(a == false)
|
||||||
|
println(false == a)
|
||||||
|
println(b == true)
|
||||||
|
println(true == b)
|
||||||
|
println(b == false)
|
||||||
|
println(false == b)
|
||||||
|
|
||||||
|
# __ne__
|
||||||
|
println("__ne__")
|
||||||
|
println(a != a)
|
||||||
|
println(a != b)
|
||||||
|
println(b != b)
|
||||||
|
println(b != a)
|
||||||
|
println(a != true)
|
||||||
|
println(true != a)
|
||||||
|
println(a != false)
|
||||||
|
println(false != a)
|
||||||
|
println(b != true)
|
||||||
|
println(true != b)
|
||||||
|
println(b != false)
|
||||||
|
println(false != b)
|
||||||
|
|
||||||
|
# constructor
|
||||||
|
println("constructor")
|
||||||
|
println(Bool(""))
|
||||||
|
println(Bool(0))
|
||||||
|
println(Bool(0.0))
|
||||||
|
println(Bool(false))
|
||||||
|
# This is a fun one. Bool constructor does *not* parse bools, it just checks if they are empty.
|
||||||
|
println(Bool("false"))
|
||||||
|
println(Bool("true"))
|
||||||
|
println(Bool(1))
|
||||||
|
println(Bool(1.0))
|
||||||
|
println(Bool(true))
|
||||||
55
tests/bool.npp.expect
Normal file
55
tests/bool.npp.expect
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
__not__
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
__and__
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
__or__
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
__eq__
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
__ne__
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
constructor
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
@@ -128,3 +128,12 @@ println(-0.0)
|
|||||||
println(--0.0)
|
println(--0.0)
|
||||||
println(---0.0)
|
println(---0.0)
|
||||||
|
|
||||||
|
# constructor
|
||||||
|
println("constructor")
|
||||||
|
println(Float("10"))
|
||||||
|
println(Float("10e3"))
|
||||||
|
println(Float("12e-3"))
|
||||||
|
println(Float(1234))
|
||||||
|
println(Float(1.5))
|
||||||
|
println(Float(true))
|
||||||
|
println(Float(false))
|
||||||
|
|||||||
@@ -96,3 +96,11 @@ __neg__
|
|||||||
-0.0
|
-0.0
|
||||||
0.0
|
0.0
|
||||||
-0.0
|
-0.0
|
||||||
|
constructor
|
||||||
|
10.0
|
||||||
|
10000.0
|
||||||
|
0.012
|
||||||
|
1234.0
|
||||||
|
1.5
|
||||||
|
1.0
|
||||||
|
0.0
|
||||||
|
|||||||
@@ -123,3 +123,11 @@ println(10 - -20)
|
|||||||
println(-10 - 20)
|
println(-10 - 20)
|
||||||
println(-10 - -20)
|
println(-10 - -20)
|
||||||
println(-0xff)
|
println(-0xff)
|
||||||
|
|
||||||
|
# constructor
|
||||||
|
println("constructor")
|
||||||
|
println(Int("10"))
|
||||||
|
println(Int(1234))
|
||||||
|
println(Int(1.5))
|
||||||
|
println(Int(true))
|
||||||
|
println(Int(false))
|
||||||
|
|||||||
@@ -93,3 +93,9 @@ __neg__
|
|||||||
-30
|
-30
|
||||||
10
|
10
|
||||||
-255
|
-255
|
||||||
|
constructor
|
||||||
|
10
|
||||||
|
1234
|
||||||
|
1
|
||||||
|
1
|
||||||
|
0
|
||||||
|
|||||||
@@ -33,8 +33,17 @@ println(a + a)
|
|||||||
println(a + a + a)
|
println(a + a + a)
|
||||||
println(a + b)
|
println(a + b)
|
||||||
println(b + a)
|
println(b + a)
|
||||||
|
|
||||||
# __mul__
|
# __mul__
|
||||||
println("__mul__")
|
println("__mul__")
|
||||||
println(a * 4)
|
println(a * 4)
|
||||||
println(b * 5)
|
println(b * 5)
|
||||||
println((a * 6).to_repr())
|
println((a * 6).to_repr())
|
||||||
|
|
||||||
|
# constructor
|
||||||
|
println("constructor")
|
||||||
|
println(Str("asdf"))
|
||||||
|
println(Str(1234))
|
||||||
|
println(Str(1.0))
|
||||||
|
println(Str(true))
|
||||||
|
println(Str(false))
|
||||||
|
|||||||
@@ -24,3 +24,9 @@ __mul__
|
|||||||
asdfasdfasdfasdf
|
asdfasdfasdfasdf
|
||||||
This is a longer sentenceThis is a longer sentenceThis is a longer sentenceThis is a longer sentenceThis is a longer sentence
|
This is a longer sentenceThis is a longer sentenceThis is a longer sentenceThis is a longer sentenceThis is a longer sentence
|
||||||
'asdfasdfasdfasdfasdfasdf'
|
'asdfasdfasdfasdfasdfasdf'
|
||||||
|
constructor
|
||||||
|
asdf
|
||||||
|
1234
|
||||||
|
1.0
|
||||||
|
true
|
||||||
|
false
|
||||||
|
|||||||
Reference in New Issue
Block a user