Add add, sub, mul, and div functions to integers
Arithmetic among integers is supportd. Yey! Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -15,7 +15,7 @@ pub static PRINTLN_BUILTIN_FUN: Lazy<NativeFunRef> = 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<NativeFunRef> = 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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Int>;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct Int {
|
||||
|
||||
impl Int {
|
||||
pub fn new_obj(value: i64) -> ObjRef<Self> {
|
||||
// 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<NativeFunRef> = 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>(int_obj.as_any()) {
|
||||
if let Some(int_obj) = Any::downcast_ref::<Int>(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<NativeFunRef> = Lazy::new(|| {
|
||||
Ok(crate::vm::signal::Signal::Return)
|
||||
})
|
||||
});
|
||||
|
||||
/// Int.__add__(self, Int) impl
|
||||
static INT_ADD_FUN: Lazy<NativeFunRef> = 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<NativeFunRef> = 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<NativeFunRef> = 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<NativeFunRef> = 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)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -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),+ $(,)?) => {{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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!(),
|
||||
|
||||
Reference in New Issue
Block a user