Most object types get their own file now
This is hopefully going to make navigating the source tree easier. Hopefully. The only types that don't get their own files are: * function types (UserFunction, BuiltinFunction, Method), which all live in obj/function.rs * Nil, which lives in obj.rs * Obj, which lives in obj.rs Type definitions and init_types now live in obj/ty.rs. New obj::prelude module for common imports. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
186
src/obj/int.rs
Normal file
186
src/obj/int.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
use gc::{Finalize, Trace};
|
||||
|
||||
use crate::obj::macros::*;
|
||||
use crate::obj::prelude::*;
|
||||
use crate::obj::BaseObj;
|
||||
use crate::vm::Vm;
|
||||
|
||||
#[derive(Trace, Finalize)]
|
||||
pub struct Int {
|
||||
base: BaseObj,
|
||||
pub(crate) int_value: i64,
|
||||
}
|
||||
|
||||
impl Int {
|
||||
pub fn new(int_value: i64) -> Self {
|
||||
Self {
|
||||
int_value,
|
||||
base: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl_create!(int_value: i64);
|
||||
|
||||
pub fn int_value(&self) -> i64 {
|
||||
self.int_value
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Int {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.int_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Int {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.int_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for Int {
|
||||
fn is_truthy(&self) -> bool {
|
||||
self.int_value != 0
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn Object) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Int>() {
|
||||
self.int_value == other.int_value
|
||||
} else if let Some(other) = other.as_any().downcast_ref::<Float>() {
|
||||
self.int_value as f64 == other.float_value()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl_base_obj!(Int);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Int implementations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! int_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, Int::int_value);
|
||||
|
||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||
Int::create(lhs_value $op int_inst.int_value())
|
||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||
Float::create(lhs_value as f64 $op float_inst.float_value())
|
||||
} else {
|
||||
// TODO Int arithmetic operator - throw an exception when RHS is not Int, Float
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!(
|
||||
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
||||
rhs.borrow().ty_name()
|
||||
)
|
||||
};
|
||||
result.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! int_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, Int::int_value);
|
||||
|
||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||
Bool::create(lhs_value $op int_inst.int_value())
|
||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||
Bool::create((lhs_value as f64) $op float_inst.float_value())
|
||||
} else {
|
||||
// TODO Int logical operator - throw an exception when RHS is not Int, Float
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!(
|
||||
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
||||
rhs.borrow().ty_name()
|
||||
)
|
||||
};
|
||||
result.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Int {
|
||||
pub(crate) fn to_int(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
FunctionResult::Return
|
||||
}
|
||||
|
||||
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
let int_value = with_obj_downcast(vm.frame_stack()[0].clone(), Int::int_value);
|
||||
Float::create(int_value as f64).into()
|
||||
}
|
||||
|
||||
impl_do_call!(to_int);
|
||||
|
||||
pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||
// This is a no-op. We don't want the user-exposed `__init__` function to do anything,
|
||||
// instantiation is done in the `__call__` function.
|
||||
FunctionResult::ReturnPush(Nil::create())
|
||||
}
|
||||
|
||||
int_bin_op_math!(add, +);
|
||||
int_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, Int::int_value);
|
||||
|
||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||
Int::create(lhs_value * int_inst.int_value())
|
||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||
Float::create(lhs_value as f64 * float_inst.float_value())
|
||||
} else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::<Str>() {
|
||||
// TODO Int::mul - maybe convert this to just call Str.mul with arguments reversed?
|
||||
// Just so we have the same logic here
|
||||
Str::create(str_inst.str_value().repeat(lhs_value as usize))
|
||||
} else {
|
||||
// TODO Int::mul - throw an exception when RHS is not Int, Float, Str
|
||||
// BLOCKED-ON: exceptions
|
||||
todo!(
|
||||
"cannot use '*' operator with Int and {}",
|
||||
rhs.borrow().ty_name()
|
||||
)
|
||||
};
|
||||
result.into()
|
||||
}
|
||||
|
||||
// TODO Int::div - handle divide by zero
|
||||
// BLOCKED-ON: exceptions
|
||||
// NOTE - we will probably need to get rid of the macro here to handle that :(
|
||||
int_bin_op_math!(div, /);
|
||||
|
||||
// __eq__ will use the default .equals implementation
|
||||
//int_bin_op_logical!(eq, ==);
|
||||
// __ne__ will call __eq__ and negate it
|
||||
int_bin_op_logical!(gt, >);
|
||||
int_bin_op_logical!(ge, >=);
|
||||
int_bin_op_logical!(lt, <);
|
||||
int_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, Int::int_value);
|
||||
Int::create(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, Int::int_value);
|
||||
Int::create(-value).into()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user