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);
|
read_obj!(let str_obj = return_value);
|
||||||
let str_obj: &Str = str_obj.as_any().downcast_ref()
|
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());
|
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);
|
read_obj!(let str_obj = return_value);
|
||||||
let str_obj: &Str = str_obj.as_any().downcast_ref()
|
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());
|
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 once_cell::sync::Lazy;
|
||||||
use shredder::Scan;
|
use shredder::Scan;
|
||||||
use std::fmt::{Debug, Formatter, self};
|
use std::{any::Any, fmt::{Debug, Formatter, self}};
|
||||||
|
|
||||||
pub type IntRef = ObjRef<Int>;
|
pub type IntRef = ObjRef<Int>;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ pub struct Int {
|
|||||||
|
|
||||||
impl Int {
|
impl Int {
|
||||||
pub fn new_obj(value: i64) -> ObjRef<Self> {
|
pub fn new_obj(value: i64) -> ObjRef<Self> {
|
||||||
// TODO : cache int values
|
// TODO(cache) : cache int values
|
||||||
self_referring_obj! {
|
self_referring_obj! {
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
@@ -24,6 +24,10 @@ impl Int {
|
|||||||
vtable: |obj_ref: ObjRef| vtable! {
|
vtable: |obj_ref: ObjRef| vtable! {
|
||||||
// TODO needs Method type so this function is given an argument when called
|
// 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()),
|
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(|| {
|
static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
NativeFun::new_obj(1, |_callee, vm, args| {
|
NativeFun::new_obj(1, |_callee, vm, args| {
|
||||||
read_obj!(let int_obj = &args[0]);
|
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()));
|
vm.push(Str::new_obj(int_obj.value.to_string()));
|
||||||
} else {
|
} else {
|
||||||
panic!("{:?} is not an int", int_obj)
|
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)
|
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_export]
|
||||||
macro_rules! attrs {
|
macro_rules! attrs {
|
||||||
($($key:expr => $value:expr),+ $(,)?) => {{
|
($($key:expr => $value:expr),+ $(,)?) => {{
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ name!(GET_ATTR_MEMBER_NAME, "__get_attr__");
|
|||||||
name!(SET_ATTR_MEMBER_NAME, "__set_attr__");
|
name!(SET_ATTR_MEMBER_NAME, "__set_attr__");
|
||||||
name!(SELF_MEMBER_NAME, "__self__");
|
name!(SELF_MEMBER_NAME, "__self__");
|
||||||
name!(FUNC_MEMBER_NAME, "__func__");
|
name!(FUNC_MEMBER_NAME, "__func__");
|
||||||
name!(STR_MEMBER_NAME, "__str__");
|
|
||||||
name!(REPR_MEMBER_NAME, "__repr__");
|
name!(REPR_MEMBER_NAME, "__repr__");
|
||||||
|
name!(STR_MEMBER_NAME, "__str__");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Predefined VM-aware symbols
|
// Predefined VM-aware symbols
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub enum Error {
|
|||||||
#[snafu(display("{}", error))]
|
#[snafu(display("{}", error))]
|
||||||
ValueError {
|
ValueError {
|
||||||
error: String,
|
error: String,
|
||||||
value: ObjRef,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
#[snafu(display("incorrect function arity; expected {} but got {} instead", expected, got))]
|
#[snafu(display("incorrect function arity; expected {} but got {} instead", expected, got))]
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ impl<'c> Vm<'c> {
|
|||||||
Signal::Call(callee, args) => {
|
Signal::Call(callee, args) => {
|
||||||
read_obj!(let callee_obj = callee);
|
read_obj!(let callee_obj = callee);
|
||||||
let frame = callee_obj.as_fun()
|
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)?;
|
.create_frame(callee.clone(), self, args)?;
|
||||||
// Jump to the first address of the new function call if it's a user function
|
// Jump to the first address of the new function call if it's a user function
|
||||||
if let Frame::User(_) = &frame {
|
if let Frame::User(_) = &frame {
|
||||||
@@ -282,18 +282,18 @@ impl<'c> Vm<'c> {
|
|||||||
let lhs = self.pop().unwrap();
|
let lhs = self.pop().unwrap();
|
||||||
let fun = {
|
let fun = {
|
||||||
read_obj!(let lhs = lhs);
|
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 => {
|
Inst::BinMinus => {
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop().unwrap();
|
||||||
let lhs = self.pop().unwrap();
|
let lhs = self.pop().unwrap();
|
||||||
let fun = {
|
let fun = {
|
||||||
read_obj!(let lhs = lhs);
|
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 => {
|
Inst::BinMul => {
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop().unwrap();
|
||||||
@@ -302,9 +302,17 @@ impl<'c> Vm<'c> {
|
|||||||
read_obj!(let lhs = lhs);
|
read_obj!(let lhs = lhs);
|
||||||
lhs.get_mul().expect("TODO: throw an error for missing __mul__ attr")
|
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 => {
|
Inst::BinEq => {
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop().unwrap();
|
||||||
let lhs = self.pop().unwrap();
|
let lhs = self.pop().unwrap();
|
||||||
@@ -312,7 +320,7 @@ impl<'c> Vm<'c> {
|
|||||||
read_obj!(let lhs = lhs);
|
read_obj!(let lhs = lhs);
|
||||||
lhs.get_eq().expect("TODO: throw an error for missing __eq__ attr")
|
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::BinNeq => todo!(),
|
||||||
Inst::BinLt => todo!(),
|
Inst::BinLt => todo!(),
|
||||||
|
|||||||
Reference in New Issue
Block a user