diff --git a/src/builtins.rs b/src/builtins.rs index c46c9aa..5d5beb4 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -187,7 +187,7 @@ impl BaseObjInst { } //////////////////////////////////////////////////////////////////////////////// -// StringInst implementations +// StrInst implementations //////////////////////////////////////////////////////////////////////////////// impl StrInst { pub(crate) fn to_str(_vm: &mut Vm, _state: FunctionState) -> FunctionResult { @@ -244,3 +244,102 @@ impl StrInst { vm.create_str(new).into() } } + +//////////////////////////////////////////////////////////////////////////////// +// IntInst implementations +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! 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, IntInst::int_value); + + let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_int(lhs_value $op int_inst.int_value()) + } else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_float(lhs_value as f64 $op float_inst.float_value()) + } else { + todo!( + concat!("cannot use '", stringify!($op), "' operator with Int and {}"), + rhs.borrow().type_name() + ) + }; + result.into() + } + } +} + +macro_rules! 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, IntInst::int_value); + + let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_bool(lhs_value $op int_inst.int_value()) + } else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_bool((lhs_value as f64) $op float_inst.float_value()) + } else { + todo!( + concat!("cannot use '", stringify!($op), "' operator with Int and {}"), + rhs.borrow().type_name() + ) + }; + result.into() + } + } +} + +impl IntInst { + bin_op_math!(add, +); + 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 + let lhs = vm.frame_stack()[0].clone(); + let rhs = vm.frame_stack()[1].clone(); + + let lhs_value = with_obj_downcast(lhs, IntInst::int_value); + + let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_int(lhs_value * int_inst.int_value()) + } else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_float(lhs_value as f64 * float_inst.float_value()) + } else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::() { + vm.create_str(str_inst.str_value().repeat(lhs_value as usize)) + } else { + todo!( + "cannot use '*' operator with Int and {}", + rhs.borrow().type_name() + ) + }; + result.into() + } + + // 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, /); + + bin_op_logical!(gt, >); + bin_op_logical!(ge, >=); + bin_op_logical!(lt, <); + 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, IntInst::int_value); + vm.create_int(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, IntInst::int_value); + vm.create_int(-value).into() + } +} diff --git a/src/obj.rs b/src/obj.rs index 70ad0e9..1f38867 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -146,7 +146,19 @@ pub fn init_types(builtins: &mut HashMap) { __add__ => builtins.create_builtin_function("__add__", StrInst::add, 2), __mul__ => builtins.create_builtin_function("__mul__", StrInst::mul, 2), }, - Int { }, + Int { + // Operators + __add__ => builtins.create_builtin_function("__add__", IntInst::add, 2), + __sub__ => builtins.create_builtin_function("__sub__", IntInst::sub, 2), + __mul__ => builtins.create_builtin_function("__mul__", IntInst::mul, 2), + __div__ => builtins.create_builtin_function("__div__", IntInst::div, 2), + __gt__ => builtins.create_builtin_function("__gt__", IntInst::gt, 2), + __ge__ => builtins.create_builtin_function("__ge__", IntInst::ge, 2), + __lt__ => builtins.create_builtin_function("__lt__", IntInst::lt, 2), + __le__ => builtins.create_builtin_function("__le__", IntInst::le, 2), + __pos__ => builtins.create_builtin_function("__pos__", IntInst::pos, 2), + __neg__ => builtins.create_builtin_function("__neg__", IntInst::neg, 2), + }, Float { }, Bool { }, Nil { }, diff --git a/src/vm.rs b/src/vm.rs index 0f555c9..0bcf371 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -265,7 +265,9 @@ impl Vm { let method_type = self.builtins().get("Method").unwrap().clone(); loop { - match self.dispatch() { + let op = self.dispatch(); + + match op { Op::Pop => { self.pop(); }