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:
2020-10-19 16:41:57 -07:00
parent 57c1aa4702
commit f35d44cf65
6 changed files with 117 additions and 16 deletions

View File

@@ -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());
}

View File

@@ -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)
})
});

View File

@@ -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),+ $(,)?) => {{

View File

@@ -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

View File

@@ -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))]

View File

@@ -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!(),