diff --git a/src/obj/builtin.rs b/src/obj/builtin.rs index c9fd651..4b4e109 100644 --- a/src/obj/builtin.rs +++ b/src/obj/builtin.rs @@ -15,7 +15,7 @@ pub static PRINTLN_BUILTIN_FUN: Lazy = Lazy::new(|| NativeFun::new { read_obj!(let str_obj = return_value); let str_obj: &Str = str_obj.as_any().downcast_ref() - .ok_or_else(|| Error::ValueError { error: "expected str value".to_string(), value: return_value.clone() })?; + .ok_or_else(|| Error::ValueError { error: "expected str value".to_string(), })?; println!("{}", str_obj.value()); } @@ -35,7 +35,7 @@ pub static PRINT_BUILTIN_FUN: Lazy = Lazy::new(|| NativeFun::new_o { read_obj!(let str_obj = return_value); let str_obj: &Str = str_obj.as_any().downcast_ref() - .ok_or_else(|| Error::ValueError { error: "expected str value".to_string(), value: return_value.clone() })?; + .ok_or_else(|| Error::ValueError { error: "expected str value".to_string(), })?; print!("{}", str_obj.value()); } diff --git a/src/obj/int.rs b/src/obj/int.rs index 405e1c8..06032f7 100644 --- a/src/obj/int.rs +++ b/src/obj/int.rs @@ -1,7 +1,7 @@ -use crate::obj::{prelude::*, reserved::*}; +use crate::{obj::{prelude::*, reserved::*}, vm::error::*}; use once_cell::sync::Lazy; use shredder::Scan; -use std::fmt::{Debug, Formatter, self}; +use std::{any::Any, fmt::{Debug, Formatter, self}}; pub type IntRef = ObjRef; @@ -14,7 +14,7 @@ pub struct Int { impl Int { pub fn new_obj(value: i64) -> ObjRef { - // TODO : cache int values + // TODO(cache) : cache int values self_referring_obj! { Self { value, @@ -24,6 +24,10 @@ impl Int { vtable: |obj_ref: ObjRef| vtable! { // TODO needs Method type so this function is given an argument when called STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()), + PLUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_ADD_FUN.clone()), + MINUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_SUB_FUN.clone()), + TIMES_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_MUL_FUN.clone()), + DIV_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_DIV_FUN.clone()), } } } @@ -43,10 +47,15 @@ impl Debug for Int { } } +//////////////////////////////////////////////////////////////////////////////// +// Builtin Int functions +//////////////////////////////////////////////////////////////////////////////// + +/// Int.__str__(self) impl static INT_STR_FUN: Lazy = Lazy::new(|| { NativeFun::new_obj(1, |_callee, vm, args| { read_obj!(let int_obj = &args[0]); - if let Some(int_obj) = std::any::Any::downcast_ref::(int_obj.as_any()) { + if let Some(int_obj) = Any::downcast_ref::(int_obj.as_any()) { vm.push(Str::new_obj(int_obj.value.to_string())); } else { panic!("{:?} is not an int", int_obj) @@ -55,3 +64,79 @@ static INT_STR_FUN: Lazy = Lazy::new(|| { Ok(crate::vm::signal::Signal::Return) }) }); + +/// Int.__add__(self, Int) impl +static INT_ADD_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let total = lhs.value + rhs.value; + vm.push(Int::new_obj(total)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__sub__(self, Int) impl +static INT_SUB_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let total = lhs.value - rhs.value; + vm.push(Int::new_obj(total)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__mul__(self, Int) impl +static INT_MUL_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let total = lhs.value * rhs.value; + vm.push(Int::new_obj(total)); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__div__(self, Int) impl +static INT_DIV_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(2, |_callee, vm, args| { + read_obj_downcast!(let lhs: Option<&Int> = &args[0]); + let lhs = lhs.ok_or_else(|| Error::ValueError { + error: "expected int for LHS".to_string(), + })?; + + read_obj_downcast!(let rhs: Option<&Int> = &args[1]); + let rhs = rhs.ok_or_else(|| Error::ValueError { + error: "expected int for RHS".to_string(), + })?; + + let total = lhs.value / rhs.value; + vm.push(Int::new_obj(total)); + Ok(crate::vm::signal::Signal::Return) + }) +}); diff --git a/src/obj/macros.rs b/src/obj/macros.rs index 91fbbc2..86ea908 100644 --- a/src/obj/macros.rs +++ b/src/obj/macros.rs @@ -74,6 +74,15 @@ macro_rules! write_obj { }; } +/// Locks a `ObjRef` type for reading and attempts to downcast it. +#[macro_export] +macro_rules! read_obj_downcast { + (let $lhs:ident : Option<&$ty:ty> = $obj:expr) => { + read_obj!(let __obj: &dyn Obj = $obj); + let $lhs: Option<&$ty> = std::any::Any::downcast_ref::<$ty>(__obj.as_any()); + }; +} + #[macro_export] macro_rules! attrs { ($($key:expr => $value:expr),+ $(,)?) => {{ diff --git a/src/obj/reserved.rs b/src/obj/reserved.rs index 3c67b70..d5f7642 100644 --- a/src/obj/reserved.rs +++ b/src/obj/reserved.rs @@ -43,8 +43,8 @@ name!(GET_ATTR_MEMBER_NAME, "__get_attr__"); name!(SET_ATTR_MEMBER_NAME, "__set_attr__"); name!(SELF_MEMBER_NAME, "__self__"); name!(FUNC_MEMBER_NAME, "__func__"); -name!(STR_MEMBER_NAME, "__str__"); name!(REPR_MEMBER_NAME, "__repr__"); +name!(STR_MEMBER_NAME, "__str__"); // // Predefined VM-aware symbols diff --git a/src/vm/error.rs b/src/vm/error.rs index e9580b3..6fd8a2a 100644 --- a/src/vm/error.rs +++ b/src/vm/error.rs @@ -11,7 +11,6 @@ pub enum Error { #[snafu(display("{}", error))] ValueError { error: String, - value: ObjRef, }, #[snafu(display("incorrect function arity; expected {} but got {} instead", expected, got))] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 1ad0c68..0a83b3e 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -149,7 +149,7 @@ impl<'c> Vm<'c> { Signal::Call(callee, args) => { read_obj!(let callee_obj = callee); let frame = callee_obj.as_fun() - .ok_or_else(|| Error::ValueError { error: "cannot call this object".to_string(), value: callee.clone() })? + .ok_or_else(|| Error::ValueError { error: "cannot call this object".to_string() })? .create_frame(callee.clone(), self, args)?; // Jump to the first address of the new function call if it's a user function if let Frame::User(_) = &frame { @@ -282,18 +282,18 @@ impl<'c> Vm<'c> { let lhs = self.pop().unwrap(); let fun = { read_obj!(let lhs = lhs); - lhs.get_plus().expect("TODO: throw an error for missing __plus__ attr") + lhs.get_plus().expect("TODO: throw an error for missing __add__ attr") }; - signal = Some(Signal::Call(fun, vec![lhs, rhs])); + signal = Some(Signal::Call(fun, vec![rhs])); } Inst::BinMinus => { let rhs = self.pop().unwrap(); let lhs = self.pop().unwrap(); let fun = { read_obj!(let lhs = lhs); - lhs.get_minus().expect("TODO: throw an error for missing __minus__ attr") + lhs.get_minus().expect("TODO: throw an error for missing __sub__ attr") }; - signal = Some(Signal::Call(fun, vec![lhs, rhs])); + signal = Some(Signal::Call(fun, vec![rhs])); } Inst::BinMul => { let rhs = self.pop().unwrap(); @@ -302,9 +302,17 @@ impl<'c> Vm<'c> { read_obj!(let lhs = lhs); lhs.get_mul().expect("TODO: throw an error for missing __mul__ attr") }; - signal = Some(Signal::Call(fun, vec![lhs, rhs])); + signal = Some(Signal::Call(fun, vec![rhs])); + } + Inst::BinDiv => { + let rhs = self.pop().unwrap(); + let lhs = self.pop().unwrap(); + let fun = { + read_obj!(let lhs = lhs); + lhs.get_div().expect("TODO: throw an error for missing __div__ attr") + }; + signal = Some(Signal::Call(fun, vec![rhs])); } - Inst::BinDiv => todo!(), Inst::BinEq => { let rhs = self.pop().unwrap(); let lhs = self.pop().unwrap(); @@ -312,7 +320,7 @@ impl<'c> Vm<'c> { read_obj!(let lhs = lhs); lhs.get_eq().expect("TODO: throw an error for missing __eq__ attr") }; - signal = Some(Signal::Call(fun, vec![lhs, rhs])); + signal = Some(Signal::Call(fun, vec![rhs])); } Inst::BinNeq => todo!(), Inst::BinLt => todo!(),