From 0d126b8ba363b0037016044ff56d576bdde6d33c Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Thu, 26 Sep 2024 09:03:13 -0700 Subject: [PATCH] Add FloatInst method implementations and tests FloatInst should be fully implemented now and have a suite of tests to make sure those methods are doing what they should be. Signed-off-by: Alek Ratzloff --- src/builtins.rs | 102 +++++++++++++++++++++++++++++--- src/obj.rs | 22 ++++++- tests/float.npp | 130 +++++++++++++++++++++++++++++++++++++++++ tests/float.npp.expect | 98 +++++++++++++++++++++++++++++++ tests/int.npp | 21 +++++++ tests/int.npp.expect | 17 ++++++ 6 files changed, 379 insertions(+), 11 deletions(-) create mode 100644 tests/float.npp create mode 100644 tests/float.npp.expect diff --git a/src/builtins.rs b/src/builtins.rs index f7d217b..e288944 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -267,7 +267,7 @@ impl StrInst { // IntInst implementations //////////////////////////////////////////////////////////////////////////////// -macro_rules! bin_op_math { +macro_rules! int_bin_op_math { ($function:ident, $op:tt) => { pub(crate) fn $function(vm: &mut Vm, _state: FunctionState) -> FunctionResult { let lhs = vm.frame_stack()[0].clone(); @@ -292,7 +292,7 @@ macro_rules! bin_op_math { } } -macro_rules! bin_op_logical { +macro_rules! int_bin_op_logical { ($function:ident, $op:tt) => { pub(crate) fn $function(vm: &mut Vm, _state: FunctionState) -> FunctionResult { let lhs = vm.frame_stack()[0].clone(); @@ -318,8 +318,8 @@ macro_rules! bin_op_logical { } impl IntInst { - bin_op_math!(add, +); - bin_op_math!(sub, -); + int_bin_op_math!(add, +); + int_bin_op_math!(sub, -); pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult { // can't bin_op_math this one because it needs the string case @@ -350,12 +350,15 @@ impl IntInst { // TODO IntInst::div - handle divide by zero // BLOCKED-ON: exceptions // NOTE - we will probably need to get rid of the macro here to handle that :( - bin_op_math!(div, /); + int_bin_op_math!(div, /); - bin_op_logical!(gt, >); - bin_op_logical!(ge, >=); - bin_op_logical!(lt, <); - bin_op_logical!(le, <=); + // __eq__ will use the default .equals implementation + //int_bin_op_logical!(eq, ==); + // __ne__ will call __eq__ and negate it + int_bin_op_logical!(gt, >); + int_bin_op_logical!(ge, >=); + int_bin_op_logical!(lt, <); + int_bin_op_logical!(le, <=); pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult { let lhs = vm.frame_stack()[0].clone(); @@ -369,3 +372,84 @@ impl IntInst { IntInst::create(-value).into() } } + +//////////////////////////////////////////////////////////////////////////////// +// FloatInst implementations +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! float_bin_op_math { + ($function:ident, $op:tt) => { + pub(crate) fn $function(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let rhs = vm.frame_stack()[1].clone(); + + let lhs_value = with_obj_downcast(lhs, FloatInst::float_value); + + let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + FloatInst::create(lhs_value $op int_inst.int_value() as f64) + } else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::() { + FloatInst::create(lhs_value $op float_inst.float_value()) + } else { + // TODO IntInst arithmetic operator - throw an exception when RHS is not Int, Float + // BLOCKED-ON: exceptions + todo!( + concat!("cannot use '", stringify!($op), "' operator with Float and {}"), + rhs.borrow().type_name() + ) + }; + result.into() + } + } +} + +macro_rules! float_bin_op_logical { + ($function:ident, $op:tt) => { + pub(crate) fn $function(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let rhs = vm.frame_stack()[1].clone(); + + let lhs_value = with_obj_downcast(lhs, FloatInst::float_value); + + let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + BoolInst::create(lhs_value $op int_inst.int_value() as f64) + } else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::() { + BoolInst::create(lhs_value $op float_inst.float_value()) + } else { + // TODO IntInst logical operator - throw an exception when RHS is not Int, Float + // BLOCKED-ON: exceptions + todo!( + concat!("cannot use '", stringify!($op), "' operator with Float and {}"), + rhs.borrow().type_name() + ) + }; + result.into() + } + } +} + +impl FloatInst { + float_bin_op_math!(add, +); + float_bin_op_math!(sub, -); + float_bin_op_math!(mul, *); + float_bin_op_math!(div, /); + + // __eq__ will use the default .equals implementation + //int_bin_op_logical!(eq, ==); + // __ne__ will call __eq__ and negate it + float_bin_op_logical!(gt, >); + float_bin_op_logical!(ge, >=); + float_bin_op_logical!(lt, <); + float_bin_op_logical!(le, <=); + + pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let value = with_obj_downcast(lhs, FloatInst::float_value); + FloatInst::create(value.abs()).into() + } + + pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let value = with_obj_downcast(lhs, FloatInst::float_value); + FloatInst::create(-value).into() + } +} diff --git a/src/obj.rs b/src/obj.rs index de3abe0..543fb28 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -156,6 +156,7 @@ pub fn init_types() { __sub__ => BuiltinFunctionInst::create("__sub__", IntInst::sub, 2), __mul__ => BuiltinFunctionInst::create("__mul__", IntInst::mul, 2), __div__ => BuiltinFunctionInst::create("__div__", IntInst::div, 2), + //__eq__ => BuiltinFunctionInst::create("__eq__", IntInst::eq, 2), __gt__ => BuiltinFunctionInst::create("__gt__", IntInst::gt, 2), __ge__ => BuiltinFunctionInst::create("__ge__", IntInst::ge, 2), __lt__ => BuiltinFunctionInst::create("__lt__", IntInst::lt, 2), @@ -163,7 +164,19 @@ pub fn init_types() { __pos__ => BuiltinFunctionInst::create("__pos__", IntInst::pos, 1), __neg__ => BuiltinFunctionInst::create("__neg__", IntInst::neg, 1), }, - Float { }, + Float { + __add__ => BuiltinFunctionInst::create("__add__", FloatInst::add, 2), + __sub__ => BuiltinFunctionInst::create("__sub__", FloatInst::sub, 2), + __mul__ => BuiltinFunctionInst::create("__mul__", FloatInst::mul, 2), + __div__ => BuiltinFunctionInst::create("__div__", FloatInst::div, 2), + + __gt__ => BuiltinFunctionInst::create("__gt__", FloatInst::gt, 2), + __ge__ => BuiltinFunctionInst::create("__ge__", FloatInst::ge, 2), + __lt__ => BuiltinFunctionInst::create("__lt__", FloatInst::lt, 2), + __le__ => BuiltinFunctionInst::create("__le__", FloatInst::le, 2), + __pos__ => BuiltinFunctionInst::create("__pos__", FloatInst::pos, 1), + __neg__ => BuiltinFunctionInst::create("__neg__", FloatInst::neg, 1), + }, Bool { }, Nil { }, BuiltinFunction { }, @@ -588,7 +601,12 @@ impl Finalize for FloatInst { impl Display for FloatInst { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}", self.float_value) + // we want to force the .0 if it's a whole number + if self.float_value == self.float_value.floor() { + write!(fmt, "{}.0", self.float_value) + } else { + write!(fmt, "{}", self.float_value) + } } } diff --git a/tests/float.npp b/tests/float.npp new file mode 100644 index 0000000..633e3d7 --- /dev/null +++ b/tests/float.npp @@ -0,0 +1,130 @@ +# Float type operator function tests + +# assign +a = 1.234 +b = 20.0 +c = 1.0 / 3.0 + +println(a) +println(b) +println(c) +println(1.1) + +# __add__ +println("__add__") +println(1 + 1.5) +println(1 + 1.25) +println(1 + 1.125) +println(a + b) + +# __sub__ +println("__sub__") +println(2.0 - 3.0) +println(1 - 1.5) +println(0.5 - 0.5) +println(b - a) + +# __mul__ +println("__mul__") +println(0.0 * -1.0) +println(-0.0 * -0.0) +println(0.0 * -0.0) +println(c * 3.0) + +# __div__ +println("__div__") +println(1 / 10.0) +println(1 / c) +println(1.0 / 2) +println(1 / (1 / 2.0)) + +# __ne__ +println("__ne__") +println(1.0 != 1.0) +println(-0.0 != 0.0) +println(2.0 != 1.0) +println(1.0 != 1) +println(1 != 1.0) +println(-0.0 != 0) +println(-0 != -0.0) +println(a != b) +println(b != c) + +# __eq__ +println("__eq__") +println(1.0 == 1.0) +println(-0.0 == 0.0) +println(2.0 == 1.0) +println(2 == 2.0) +println(2.0 == 2) +println(-0.0 == 0) +println(0 == -0.0) +println(a == b) +println(b == c) + +# __gt__ +println("__gt__") +println(1.0 > 1.0) +println(1 > 0.0) +println(1 > -0.0) +println(0.0 > -1) +println(-0.0 > -1) +println(-1.0 > 0) +println(-2.0 > -1.0) + +# __ge__ +println("__ge__") +println(1.0 >= 1.0) +println(1.0 >= 1) +println(2.0 >= 1.0) +println(1 >= 2.0) +println(0.0 >= 0.0) +println(0.0 >= -0.0) +println(0.0 >= -1.0) +println(-1.0 >= 0.0) +println(-2.0 >= -1.0) + +# __lt__ +println("__lt__") +println(1.0 < 1.0) +println(1.0 < 1) +println(1 < 1.0) +println(1.0 < 2.0) +println(2.0 < 1.0) +println(1 < 2.0) +println(2.0 < 1.0) +println(1 < 0.0) +println(1 < 1.0) +println(0.0 < -0.0) +println(-0.0 < 0) +println(-1.0 < -2.0) +println(-2.0 < -1.0) + +# __le__ +println("__le__") +println(1.0 <= 1.0) +println(1.0 <= 1) +println(1 <= 1.0) +println(1.0 <= 2.0) +println(2.0 <= 1.0) +println(1 <= 2.0) +println(2.0 <= 1.0) +println(1 <= 0.0) +println(1 <= 1.0) +println(0.0 <= -0.0) +println(-0.0 <= 0) +println(-1.0 <= -2.0) +println(-2.0 <= -1.0) + +# __pos__ +println("__pos__") +println(+1.0) +println(+(-0.0)) +println(++(-0.0)) + +# __neg__ +println("__neg__") +println(-0.0) +println(--0.0) +println(---0.0) + diff --git a/tests/float.npp.expect b/tests/float.npp.expect new file mode 100644 index 0000000..1c3beac --- /dev/null +++ b/tests/float.npp.expect @@ -0,0 +1,98 @@ +1.234 +20.0 +0.3333333333333333 +1.1 +__add__ +2.5 +2.25 +2.125 +21.234 +__sub__ +-1.0 +-0.5 +0.0 +18.766 +__mul__ +-0.0 +0.0 +-0.0 +1.0 +__div__ +0.1 +3.0 +0.5 +2.0 +__ne__ +false +false +true +false +false +false +false +true +true +__eq__ +true +true +false +true +true +true +true +false +false +__gt__ +false +true +true +true +true +false +false +__ge__ +true +true +true +false +true +true +true +false +false +__lt__ +false +false +false +true +false +true +false +false +false +false +false +false +true +__le__ +true +true +true +true +false +true +false +false +true +true +true +false +true +__pos__ +1.0 +0.0 +0.0 +__neg__ +-0.0 +0.0 +-0.0 diff --git a/tests/int.npp b/tests/int.npp index 42609fc..bd4fa3d 100644 --- a/tests/int.npp +++ b/tests/int.npp @@ -14,6 +14,8 @@ println(1 + 2 + 3) println(1938 + 481) println(a + b) println(b + a) +println(a + -b) +println(-a + b) # __sub__ println("__sub__") @@ -47,6 +49,25 @@ println(3 / 363) println(a / b) println(b / a) +# __ne__ +println("__ne__") +println(1 != 1) +println(1 != 2) +println(1 != 1.0) +println(1 != 2.0) +println(2 != 3839) +println(3284 != 922) +println(2 * 3 != 4 * 5) + +# __eq__ +println("__eq__") +println(1 == 1) +println(1 == 2) +println(1 == 1.0) +println(1 == 2.0) +println(6139 == 130) +println(1000 == 1001) + # __gt__ println("__gt__") println(1 > 2) diff --git a/tests/int.npp.expect b/tests/int.npp.expect index 2c37397..31e766b 100644 --- a/tests/int.npp.expect +++ b/tests/int.npp.expect @@ -6,6 +6,8 @@ __add__ 2419 30 30 +-10 +10 __sub__ -1 1 @@ -32,6 +34,21 @@ __div__ 0 0 2 +__ne__ +false +true +false +true +true +true +true +__eq__ +true +false +true +false +false +false __gt__ false true