Big Object naming refactor
* trait Obj -> Object * Remove *Inst suffix from all object types. ObjInst -> Obj, IntInst -> Int, etc * Type -> Ty, type_inst() -> ty(), type_name() -> ty_name() Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
181
src/builtins.rs
181
src/builtins.rs
@@ -1,5 +1,5 @@
|
|||||||
//! Builtin functions.
|
//! Builtin functions.
|
||||||
use crate::obj::function::{BuiltinFunctionInst, FunctionResult, FunctionState};
|
use crate::obj::function::{BuiltinFunction, FunctionResult, FunctionState};
|
||||||
use crate::obj::*;
|
use crate::obj::*;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ pub fn init_global_builtins() {
|
|||||||
macro_rules! builtins {
|
macro_rules! builtins {
|
||||||
($($builtin:ident / $argc:expr),* $(,)?) => {
|
($($builtin:ident / $argc:expr),* $(,)?) => {
|
||||||
$({
|
$({
|
||||||
let builtin_function = BuiltinFunctionInst::create(stringify!($builtin), $builtin, $argc);
|
let builtin_function = BuiltinFunction::create(stringify!($builtin), $builtin, $argc);
|
||||||
$crate::obj::BUILTINS.with_borrow_mut(|builtins|
|
$crate::obj::BUILTINS.with_borrow_mut(|builtins|
|
||||||
builtins.insert(
|
builtins.insert(
|
||||||
stringify!($builtin).to_string(),
|
stringify!($builtin).to_string(),
|
||||||
@@ -50,7 +50,7 @@ pub(crate) fn println(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
|||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
println!("{}", vm.frame_stack()[0].borrow());
|
println!("{}", vm.frame_stack()[0].borrow());
|
||||||
NilInst::create().into()
|
Nil::create().into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -69,17 +69,17 @@ pub(crate) fn print(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
|||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
print!("{}", vm.frame_stack()[0].borrow());
|
print!("{}", vm.frame_stack()[0].borrow());
|
||||||
NilInst::create().into()
|
Nil::create().into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BaseObjInst implementations
|
// BaseObj implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl BaseObjInst {
|
impl BaseObj {
|
||||||
//
|
//
|
||||||
// Common functions
|
// Common functions
|
||||||
//
|
//
|
||||||
@@ -103,11 +103,11 @@ impl BaseObjInst {
|
|||||||
|
|
||||||
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let str_value = format!("{}", vm.frame_stack()[0].borrow());
|
let str_value = format!("{}", vm.frame_stack()[0].borrow());
|
||||||
StrInst::create(str_value).into()
|
Str::create(str_value).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
BoolInst::create(vm.frame_stack()[0].borrow().is_truthy()).into()
|
Bool::create(vm.frame_stack()[0].borrow().is_truthy()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -118,14 +118,14 @@ impl BaseObjInst {
|
|||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let result = lhs.is_truthy() && rhs.is_truthy();
|
let result = lhs.is_truthy() && rhs.is_truthy();
|
||||||
BoolInst::create(result).into()
|
Bool::create(result).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn or(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn or(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let result = lhs.is_truthy() || rhs.is_truthy();
|
let result = lhs.is_truthy() || rhs.is_truthy();
|
||||||
BoolInst::create(result).into()
|
Bool::create(result).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ne(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
pub(crate) fn ne(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||||
@@ -145,7 +145,7 @@ impl BaseObjInst {
|
|||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
let result = !vm.peek().borrow().is_truthy();
|
let result = !vm.peek().borrow().is_truthy();
|
||||||
BoolInst::create(result).into()
|
Bool::create(result).into()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -157,7 +157,7 @@ impl BaseObjInst {
|
|||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let equals = lhs.equals(&*rhs);
|
let equals = lhs.equals(&*rhs);
|
||||||
BoolInst::create(equals).into()
|
Bool::create(equals).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn not(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
pub(crate) fn not(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||||
@@ -173,7 +173,7 @@ impl BaseObjInst {
|
|||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
let value = vm.peek().borrow().is_truthy();
|
let value = vm.peek().borrow().is_truthy();
|
||||||
BoolInst::create(!value).into()
|
Bool::create(!value).into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ impl BaseObjInst {
|
|||||||
|
|
||||||
pub(crate) fn not_implemented_un(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn not_implemented_un(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let fname = &vm.frame().name;
|
let fname = &vm.frame().name;
|
||||||
// TODO BaseObjInst::not_implemented_un - throw an exception of some kind for not
|
// TODO BaseObj::not_implemented_un - throw an exception of some kind for not
|
||||||
// implemented/not available errors on unary operators
|
// implemented/not available errors on unary operators
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
@@ -196,7 +196,7 @@ impl BaseObjInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn not_implemented_bin(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn not_implemented_bin(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
// TODO BaseObjInst::not_implemented_un - throw an exception of some kind for not
|
// TODO BaseObj::not_implemented_un - throw an exception of some kind for not
|
||||||
// implemented/not available errors on unary operators
|
// implemented/not available errors on unary operators
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
let fname = &vm.frame().name;
|
let fname = &vm.frame().name;
|
||||||
@@ -205,30 +205,29 @@ impl BaseObjInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// StrInst implementations
|
// Str implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
impl StrInst {
|
impl Str {
|
||||||
pub(crate) fn to_str(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_str(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
// top item of the stack should just be ourselves, so return immediately
|
// top item of the stack should just be ourselves, so return immediately
|
||||||
FunctionResult::Return
|
FunctionResult::Return
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let escaped: String =
|
let escaped: String = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &Str| {
|
||||||
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
|
||||||
str_inst.str_value().as_str().escape_default().collect()
|
str_inst.str_value().as_str().escape_default().collect()
|
||||||
});
|
});
|
||||||
StrInst::create(format!("'{}'", escaped)).into()
|
Str::create(format!("'{}'", escaped)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let parsed: Result<i64, _> =
|
let parsed: Result<i64, _> =
|
||||||
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &Str| {
|
||||||
str_inst.str_value().parse()
|
str_inst.str_value().parse()
|
||||||
});
|
});
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok(int) => IntInst::create(int).into(),
|
Ok(int) => Int::create(int).into(),
|
||||||
// TODO StrInst::to_int - throw an exception when we fail to parse an integer
|
// TODO Str::to_int - throw an exception when we fail to parse an integer
|
||||||
// BLOCKED-ON - exceptions
|
// BLOCKED-ON - exceptions
|
||||||
Err(e) => todo!("error parsing string to an integer: {}", e),
|
Err(e) => todo!("error parsing string to an integer: {}", e),
|
||||||
}
|
}
|
||||||
@@ -236,61 +235,61 @@ impl StrInst {
|
|||||||
|
|
||||||
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let parsed: Result<f64, _> =
|
let parsed: Result<f64, _> =
|
||||||
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &Str| {
|
||||||
str_inst.str_value().parse()
|
str_inst.str_value().parse()
|
||||||
});
|
});
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok(float) => FloatInst::create(float).into(),
|
Ok(float) => Float::create(float).into(),
|
||||||
// TODO StrInst::to_int - throw an exception when we fail to parse an integer
|
// TODO Str::to_int - throw an exception when we fail to parse an integer
|
||||||
// BLOCKED-ON - exceptions
|
// BLOCKED-ON - exceptions
|
||||||
Err(e) => todo!("error parsing string to a float: {}", e),
|
Err(e) => todo!("error parsing string to a float: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn len(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn len(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let len = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
let len = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &Str| {
|
||||||
str_inst.str_value().len() as i64
|
str_inst.str_value().len() as i64
|
||||||
});
|
});
|
||||||
IntInst::create(len).into()
|
Int::create(len).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn add(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
if !obj_is_inst::<StrInst>(&rhs) {
|
if !obj_is_inst::<Str>(&rhs) {
|
||||||
// TODO StrInst::add - throw an exception when the RHS is not a string
|
// TODO Str::add - throw an exception when the RHS is not a string
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
"can only concatenate Str, got {} instead",
|
"can only concatenate Str, got {} instead",
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let new = format!("{}{}", lhs.borrow(), rhs.borrow());
|
let new = format!("{}{}", lhs.borrow(), rhs.borrow());
|
||||||
StrInst::create(new).into()
|
Str::create(new).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
let repeat_count = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let repeat_count = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
int_inst.int_value()
|
int_inst.int_value()
|
||||||
} else {
|
} else {
|
||||||
// TODO StrInst::mul - throw an exception when the RHS is not an int
|
// TODO Str::mul - throw an exception when the RHS is not an int
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
"can only repeat Str with Int, got {} instead",
|
"can only repeat Str with Int, got {} instead",
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let repeat_count = repeat_count.max(0) as usize;
|
let repeat_count = repeat_count.max(0) as usize;
|
||||||
let new = format!("{}", lhs.borrow()).repeat(repeat_count);
|
let new = format!("{}", lhs.borrow()).repeat(repeat_count);
|
||||||
StrInst::create(new).into()
|
Str::create(new).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// IntInst implementations
|
// Int implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! int_bin_op_math {
|
macro_rules! int_bin_op_math {
|
||||||
@@ -299,18 +298,18 @@ macro_rules! int_bin_op_math {
|
|||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
|
|
||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, Int::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
IntInst::create(lhs_value $op int_inst.int_value())
|
Int::create(lhs_value $op int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||||
FloatInst::create(lhs_value as f64 $op float_inst.float_value())
|
Float::create(lhs_value as f64 $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst arithmetic operator - throw an exception when RHS is not Int, Float
|
// TODO Int arithmetic operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
result.into()
|
result.into()
|
||||||
@@ -324,18 +323,18 @@ macro_rules! int_bin_op_logical {
|
|||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
|
|
||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, Int::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
BoolInst::create(lhs_value $op int_inst.int_value())
|
Bool::create(lhs_value $op int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||||
BoolInst::create((lhs_value as f64) $op float_inst.float_value())
|
Bool::create((lhs_value as f64) $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst logical operator - throw an exception when RHS is not Int, Float
|
// TODO Int logical operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
concat!("cannot use '", stringify!($op), "' operator with Int and {}"),
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
result.into()
|
result.into()
|
||||||
@@ -343,14 +342,14 @@ macro_rules! int_bin_op_logical {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntInst {
|
impl Int {
|
||||||
pub(crate) fn to_int(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_int(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
FunctionResult::Return
|
FunctionResult::Return
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_float(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let int_value = with_obj_downcast(vm.frame_stack()[0].clone(), IntInst::int_value);
|
let int_value = with_obj_downcast(vm.frame_stack()[0].clone(), Int::int_value);
|
||||||
FloatInst::create(int_value as f64).into()
|
Float::create(int_value as f64).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
int_bin_op_math!(add, +);
|
int_bin_op_math!(add, +);
|
||||||
@@ -361,28 +360,28 @@ impl IntInst {
|
|||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
|
|
||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, Int::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
IntInst::create(lhs_value * int_inst.int_value())
|
Int::create(lhs_value * int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||||
FloatInst::create(lhs_value as f64 * float_inst.float_value())
|
Float::create(lhs_value as f64 * float_inst.float_value())
|
||||||
} else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::<StrInst>() {
|
} else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::<Str>() {
|
||||||
// TODO IntInst::mul - maybe convert this to just call Str.mul with arguments reversed?
|
// TODO Int::mul - maybe convert this to just call Str.mul with arguments reversed?
|
||||||
// Just so we have the same logic here
|
// Just so we have the same logic here
|
||||||
StrInst::create(str_inst.str_value().repeat(lhs_value as usize))
|
Str::create(str_inst.str_value().repeat(lhs_value as usize))
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst::mul - throw an exception when RHS is not Int, Float, Str
|
// TODO Int::mul - throw an exception when RHS is not Int, Float, Str
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
"cannot use '*' operator with Int and {}",
|
"cannot use '*' operator with Int and {}",
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
result.into()
|
result.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO IntInst::div - handle divide by zero
|
// TODO Int::div - handle divide by zero
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
// NOTE - we will probably need to get rid of the macro here to handle that :(
|
// NOTE - we will probably need to get rid of the macro here to handle that :(
|
||||||
int_bin_op_math!(div, /);
|
int_bin_op_math!(div, /);
|
||||||
@@ -397,19 +396,19 @@ impl IntInst {
|
|||||||
|
|
||||||
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, IntInst::int_value);
|
let value = with_obj_downcast(lhs, Int::int_value);
|
||||||
IntInst::create(value.abs()).into()
|
Int::create(value.abs()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, IntInst::int_value);
|
let value = with_obj_downcast(lhs, Int::int_value);
|
||||||
IntInst::create(-value).into()
|
Int::create(-value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// FloatInst implementations
|
// Float implementations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! float_bin_op_math {
|
macro_rules! float_bin_op_math {
|
||||||
@@ -418,18 +417,18 @@ macro_rules! float_bin_op_math {
|
|||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
|
|
||||||
let lhs_value = with_obj_downcast(lhs, FloatInst::float_value);
|
let lhs_value = with_obj_downcast(lhs, Float::float_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
FloatInst::create(lhs_value $op int_inst.int_value() as f64)
|
Float::create(lhs_value $op int_inst.int_value() as f64)
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||||
FloatInst::create(lhs_value $op float_inst.float_value())
|
Float::create(lhs_value $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst arithmetic operator - throw an exception when RHS is not Int, Float
|
// TODO Int arithmetic operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
concat!("cannot use '", stringify!($op), "' operator with Float and {}"),
|
concat!("cannot use '", stringify!($op), "' operator with Float and {}"),
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
result.into()
|
result.into()
|
||||||
@@ -443,18 +442,18 @@ macro_rules! float_bin_op_logical {
|
|||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
|
|
||||||
let lhs_value = with_obj_downcast(lhs, FloatInst::float_value);
|
let lhs_value = with_obj_downcast(lhs, Float::float_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<Int>() {
|
||||||
BoolInst::create(lhs_value $op int_inst.int_value() as f64)
|
Bool::create(lhs_value $op int_inst.int_value() as f64)
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<Float>() {
|
||||||
BoolInst::create(lhs_value $op float_inst.float_value())
|
Bool::create(lhs_value $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst logical operator - throw an exception when RHS is not Int, Float
|
// TODO Int logical operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!(
|
todo!(
|
||||||
concat!("cannot use '", stringify!($op), "' operator with Float and {}"),
|
concat!("cannot use '", stringify!($op), "' operator with Float and {}"),
|
||||||
rhs.borrow().type_name()
|
rhs.borrow().ty_name()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
result.into()
|
result.into()
|
||||||
@@ -462,10 +461,10 @@ macro_rules! float_bin_op_logical {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatInst {
|
impl Float {
|
||||||
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_int(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let float_value = with_obj_downcast(vm.frame_stack()[0].clone(), FloatInst::float_value);
|
let float_value = with_obj_downcast(vm.frame_stack()[0].clone(), Float::float_value);
|
||||||
IntInst::create(float_value as i64).into()
|
Int::create(float_value as i64).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_float(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_float(_vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
@@ -487,13 +486,13 @@ impl FloatInst {
|
|||||||
|
|
||||||
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, FloatInst::float_value);
|
let value = with_obj_downcast(lhs, Float::float_value);
|
||||||
FloatInst::create(value.abs()).into()
|
Float::create(value.abs()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, FloatInst::float_value);
|
let value = with_obj_downcast(lhs, Float::float_value);
|
||||||
FloatInst::create(-value).into()
|
Float::create(-value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use common_macros::hash_map;
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::obj::function::UserFunctionInst;
|
use crate::obj::function::UserFunction;
|
||||||
use crate::obj::*;
|
use crate::obj::*;
|
||||||
use crate::token::TokenKind;
|
use crate::token::TokenKind;
|
||||||
use crate::vm::*;
|
use crate::vm::*;
|
||||||
@@ -665,11 +665,7 @@ impl StmtVisitor for Compiler {
|
|||||||
// object created, if it were a function object, will be what we're assigning it to, but I
|
// object created, if it were a function object, will be what we're assigning it to, but I
|
||||||
// want to be 100% sure instead of 99%.
|
// want to be 100% sure instead of 99%.
|
||||||
let obj = self.constants.last().unwrap().as_ref();
|
let obj = self.constants.last().unwrap().as_ref();
|
||||||
if let Some(fun) = obj
|
if let Some(fun) = obj.borrow_mut().as_any_mut().downcast_mut::<UserFunction>() {
|
||||||
.borrow_mut()
|
|
||||||
.as_any_mut()
|
|
||||||
.downcast_mut::<UserFunctionInst>()
|
|
||||||
{
|
|
||||||
fun.set_name(Rc::new(name.to_string()));
|
fun.set_name(Rc::new(name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,7 +674,7 @@ impl StmtVisitor for Compiler {
|
|||||||
|
|
||||||
fn visit_set_stmt(&mut self, stmt: &SetStmt) -> Result<()> {
|
fn visit_set_stmt(&mut self, stmt: &SetStmt) -> Result<()> {
|
||||||
self.compile_expr(&stmt.expr)?;
|
self.compile_expr(&stmt.expr)?;
|
||||||
let name = self.insert_constant(StrInst::create(&stmt.name.text))?;
|
let name = self.insert_constant(Str::create(&stmt.name.text))?;
|
||||||
self.compile_expr(&stmt.rhs)?;
|
self.compile_expr(&stmt.rhs)?;
|
||||||
self.emit(stmt_line_number(stmt), Op::SetAttr(name));
|
self.emit(stmt_line_number(stmt), Op::SetAttr(name));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -697,7 +693,7 @@ impl StmtVisitor for Compiler {
|
|||||||
if let Some(expr) = &stmt.expr {
|
if let Some(expr) = &stmt.expr {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
} else {
|
} else {
|
||||||
let nil = self.insert_constant(NilInst::create())?;
|
let nil = self.insert_constant(Nil::create())?;
|
||||||
self.emit(stmt_line_number(stmt), Op::PushConstant(nil));
|
self.emit(stmt_line_number(stmt), Op::PushConstant(nil));
|
||||||
}
|
}
|
||||||
self.emit(stmt_line_number(stmt), Op::Return);
|
self.emit(stmt_line_number(stmt), Op::Return);
|
||||||
@@ -707,7 +703,7 @@ impl StmtVisitor for Compiler {
|
|||||||
// condition
|
// condition
|
||||||
self.compile_expr(&stmt.condition)?;
|
self.compile_expr(&stmt.condition)?;
|
||||||
// call obj.to_bool()
|
// call obj.to_bool()
|
||||||
let bool_attr = self.insert_constant(StrInst::create("to_bool"))?;
|
let bool_attr = self.insert_constant(Str::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*stmt.condition), Op::GetAttr(bool_attr));
|
self.emit(expr_line_number(&*stmt.condition), Op::GetAttr(bool_attr));
|
||||||
self.emit(expr_line_number(&*stmt.condition), Op::Call(0));
|
self.emit(expr_line_number(&*stmt.condition), Op::Call(0));
|
||||||
let condition_patch_index = self.chunk().code.len();
|
let condition_patch_index = self.chunk().code.len();
|
||||||
@@ -779,7 +775,7 @@ impl ExprVisitor for Compiler {
|
|||||||
let mut exit_patch_index = 0;
|
let mut exit_patch_index = 0;
|
||||||
|
|
||||||
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
||||||
let constant_id = self.insert_constant(StrInst::create("to_bool"))?;
|
let constant_id = self.insert_constant(Str::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*expr.lhs), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(&*expr.lhs), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(&*expr.lhs), Op::Call(0));
|
self.emit(expr_line_number(&*expr.lhs), Op::Call(0));
|
||||||
exit_patch_index = self.chunk().code.len();
|
exit_patch_index = self.chunk().code.len();
|
||||||
@@ -793,14 +789,14 @@ impl ExprVisitor for Compiler {
|
|||||||
let name = OP_NAMES
|
let name = OP_NAMES
|
||||||
.get(&expr.op.kind)
|
.get(&expr.op.kind)
|
||||||
.expect("invalid binary operator");
|
.expect("invalid binary operator");
|
||||||
let constant_id = self.insert_constant(StrInst::create(name))?;
|
let constant_id = self.insert_constant(Str::create(name))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
|
|
||||||
self.compile_expr(&expr.rhs)?;
|
self.compile_expr(&expr.rhs)?;
|
||||||
|
|
||||||
// convert RHS to a bool if we're doing AND or OR
|
// convert RHS to a bool if we're doing AND or OR
|
||||||
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
||||||
let constant_id = self.insert_constant(StrInst::create("to_bool"))?;
|
let constant_id = self.insert_constant(Str::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*expr.rhs), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(&*expr.rhs), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(&*expr.rhs), Op::Call(0));
|
self.emit(expr_line_number(&*expr.rhs), Op::Call(0));
|
||||||
}
|
}
|
||||||
@@ -838,7 +834,7 @@ impl ExprVisitor for Compiler {
|
|||||||
});
|
});
|
||||||
self.compile_expr(&expr.expr)?;
|
self.compile_expr(&expr.expr)?;
|
||||||
let name = OP_NAMES.get(&expr.op.kind).expect("invalid unary operator");
|
let name = OP_NAMES.get(&expr.op.kind).expect("invalid unary operator");
|
||||||
let constant_id = self.insert_constant(StrInst::create(name))?;
|
let constant_id = self.insert_constant(Str::create(name))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(expr), Op::Call(0));
|
self.emit(expr_line_number(expr), Op::Call(0));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -862,7 +858,7 @@ impl ExprVisitor for Compiler {
|
|||||||
|
|
||||||
fn visit_get_expr(&mut self, expr: &GetExpr) -> Result<()> {
|
fn visit_get_expr(&mut self, expr: &GetExpr) -> Result<()> {
|
||||||
self.compile_expr(&expr.expr)?;
|
self.compile_expr(&expr.expr)?;
|
||||||
let constant_id = self.insert_constant(StrInst::create(&expr.name.text))?;
|
let constant_id = self.insert_constant(Str::create(&expr.name.text))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -888,29 +884,28 @@ impl ExprVisitor for Compiler {
|
|||||||
}
|
}
|
||||||
TokenKind::Number => {
|
TokenKind::Number => {
|
||||||
let obj = if expr.token.text.contains('.') {
|
let obj = if expr.token.text.contains('.') {
|
||||||
FloatInst::create(expr.token.text.parse().unwrap())
|
Float::create(expr.token.text.parse().unwrap())
|
||||||
} else if expr.token.text.starts_with("0x") || expr.token.text.starts_with("0X") {
|
} else if expr.token.text.starts_with("0x") || expr.token.text.starts_with("0X") {
|
||||||
IntInst::create(i64::from_str_radix(&expr.token.text[2..], 16).unwrap())
|
Int::create(i64::from_str_radix(&expr.token.text[2..], 16).unwrap())
|
||||||
} else if expr.token.text.starts_with("0b") || expr.token.text.starts_with("0B") {
|
} else if expr.token.text.starts_with("0b") || expr.token.text.starts_with("0B") {
|
||||||
IntInst::create(i64::from_str_radix(&expr.token.text[2..], 2).unwrap())
|
Int::create(i64::from_str_radix(&expr.token.text[2..], 2).unwrap())
|
||||||
} else {
|
} else {
|
||||||
IntInst::create(expr.token.text.parse().unwrap())
|
Int::create(expr.token.text.parse().unwrap())
|
||||||
};
|
};
|
||||||
let constant_id = self.insert_constant(obj)?;
|
let constant_id = self.insert_constant(obj)?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::String => {
|
TokenKind::String => {
|
||||||
let constant_id =
|
let constant_id = self.insert_constant(Str::create(unescape(&expr.token.text)))?;
|
||||||
self.insert_constant(StrInst::create(unescape(&expr.token.text)))?;
|
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::True | TokenKind::False => {
|
TokenKind::True | TokenKind::False => {
|
||||||
let constant_id =
|
let constant_id =
|
||||||
self.insert_constant(BoolInst::create(expr.token.kind == TokenKind::True))?;
|
self.insert_constant(Bool::create(expr.token.kind == TokenKind::True))?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::Nil => {
|
TokenKind::Nil => {
|
||||||
let constant_id = self.insert_constant(NilInst::create())?;
|
let constant_id = self.insert_constant(Nil::create())?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@@ -968,7 +963,7 @@ impl ExprVisitor for Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always end with a "return nil"
|
// always end with a "return nil"
|
||||||
let nil = self.insert_constant(NilInst::create())?;
|
let nil = self.insert_constant(Nil::create())?;
|
||||||
self.emit(end_line, Op::PushConstant(nil));
|
self.emit(end_line, Op::PushConstant(nil));
|
||||||
self.emit(end_line, Op::Return);
|
self.emit(end_line, Op::Return);
|
||||||
|
|
||||||
@@ -976,7 +971,7 @@ impl ExprVisitor for Compiler {
|
|||||||
|
|
||||||
// create the function
|
// create the function
|
||||||
let chunk = self.chunks.pop().unwrap();
|
let chunk = self.chunks.pop().unwrap();
|
||||||
let fun = UserFunctionInst::create(chunk, expr.params.len() as Argc);
|
let fun = UserFunction::create(chunk, expr.params.len() as Argc);
|
||||||
|
|
||||||
// register the function as a constant
|
// register the function as a constant
|
||||||
let fun_constant = self.insert_constant(fun)?;
|
let fun_constant = self.insert_constant(fun)?;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::obj::function::UserFunctionInst;
|
use crate::obj::function::UserFunction;
|
||||||
use crate::obj::ObjP;
|
use crate::obj::ObjP;
|
||||||
use crate::vm::{Chunk, JumpOpArg, Op};
|
use crate::vm::{Chunk, JumpOpArg, Op};
|
||||||
|
|
||||||
@@ -151,11 +151,7 @@ pub fn disassemble(chunk: &Chunk, constants: &Vec<ObjP>, globals: &Vec<String>)
|
|||||||
disassemble_chunk(chunk, constants, globals);
|
disassemble_chunk(chunk, constants, globals);
|
||||||
|
|
||||||
for constant in constants {
|
for constant in constants {
|
||||||
if let Some(fun) = constant
|
if let Some(fun) = constant.borrow().as_any().downcast_ref::<UserFunction>() {
|
||||||
.borrow()
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<UserFunctionInst>()
|
|
||||||
{
|
|
||||||
println!();
|
println!();
|
||||||
println!(
|
println!(
|
||||||
"== {} starting on line {}",
|
"== {} starting on line {}",
|
||||||
|
|||||||
375
src/obj.rs
375
src/obj.rs
@@ -18,7 +18,7 @@ use crate::obj::macros::*;
|
|||||||
use crate::vm::{Argc, Vm};
|
use crate::vm::{Argc, Vm};
|
||||||
|
|
||||||
pub type Ptr<T> = Gc<GcCell<T>>;
|
pub type Ptr<T> = Gc<GcCell<T>>;
|
||||||
pub type ObjP = Ptr<dyn Obj>;
|
pub type ObjP = Ptr<dyn Object>;
|
||||||
pub type Attrs = HashMap<String, ObjP>;
|
pub type Attrs = HashMap<String, ObjP>;
|
||||||
|
|
||||||
// TODO obj::with_obj_downcast - optimize downcasts of "known" types with an unchecked downcast
|
// TODO obj::with_obj_downcast - optimize downcasts of "known" types with an unchecked downcast
|
||||||
@@ -26,7 +26,7 @@ pub type Attrs = HashMap<String, ObjP>;
|
|||||||
/// Downcast an object pointer to a concrete type, and do something with that object.
|
/// Downcast an object pointer to a concrete type, and do something with that object.
|
||||||
pub fn with_obj_downcast<T, Out>(ptr: ObjP, closure: impl FnOnce(&T) -> Out) -> Out
|
pub fn with_obj_downcast<T, Out>(ptr: ObjP, closure: impl FnOnce(&T) -> Out) -> Out
|
||||||
where
|
where
|
||||||
T: Obj + 'static,
|
T: Object + 'static,
|
||||||
{
|
{
|
||||||
let borrowed = ptr.borrow();
|
let borrowed = ptr.borrow();
|
||||||
if let Some(obj) = borrowed.as_any().downcast_ref::<T>() {
|
if let Some(obj) = borrowed.as_any().downcast_ref::<T>() {
|
||||||
@@ -43,7 +43,7 @@ where
|
|||||||
/// Downcast an object pointer to a concrete type, and do something with that object.
|
/// Downcast an object pointer to a concrete type, and do something with that object.
|
||||||
pub fn with_obj_downcast_mut<T, Out>(ptr: ObjP, closure: impl FnOnce(&mut T) -> Out) -> Out
|
pub fn with_obj_downcast_mut<T, Out>(ptr: ObjP, closure: impl FnOnce(&mut T) -> Out) -> Out
|
||||||
where
|
where
|
||||||
T: Obj + 'static,
|
T: Object + 'static,
|
||||||
{
|
{
|
||||||
let mut borrowed = ptr.borrow_mut();
|
let mut borrowed = ptr.borrow_mut();
|
||||||
if let Some(obj) = borrowed.as_any_mut().downcast_mut::<T>() {
|
if let Some(obj) = borrowed.as_any_mut().downcast_mut::<T>() {
|
||||||
@@ -59,15 +59,15 @@ where
|
|||||||
|
|
||||||
pub fn obj_is_inst<T>(ptr: &ObjP) -> bool
|
pub fn obj_is_inst<T>(ptr: &ObjP) -> bool
|
||||||
where
|
where
|
||||||
T: Obj + 'static,
|
T: Object + 'static,
|
||||||
{
|
{
|
||||||
let borrowed = ptr.borrow();
|
let borrowed = ptr.borrow();
|
||||||
borrowed.as_any().downcast_ref::<T>().is_some()
|
borrowed.as_any().downcast_ref::<T>().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upcast_obj<T: Obj>(ptr: Ptr<T>) -> ObjP {
|
pub fn upcast_obj<T: Object>(ptr: Ptr<T>) -> ObjP {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = Ptr::into_raw(ptr) as *const GcCell<dyn Obj>;
|
let ptr = Ptr::into_raw(ptr) as *const GcCell<dyn Object>;
|
||||||
Ptr::from_raw(ptr)
|
Ptr::from_raw(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ pub fn init_types() {
|
|||||||
),* $(,)?
|
),* $(,)?
|
||||||
) => {{
|
) => {{
|
||||||
$(
|
$(
|
||||||
let $name = make_ptr(TypeInst::new(stringify!($name)));
|
let $name = make_ptr(Ty::new(stringify!($name)));
|
||||||
BUILTINS.with_borrow_mut(|builtins| builtins.insert(stringify!($name).to_string(), $name.clone()));
|
BUILTINS.with_borrow_mut(|builtins| builtins.insert(stringify!($name).to_string(), $name.clone()));
|
||||||
)*
|
)*
|
||||||
|
|
||||||
@@ -97,16 +97,16 @@ pub fn init_types() {
|
|||||||
// setting up these fundamental types.
|
// setting up these fundamental types.
|
||||||
$({
|
$({
|
||||||
let base_type = $base_type.clone();
|
let base_type = $base_type.clone();
|
||||||
$name.borrow_mut().set_attr("__type__", base_type);
|
$name.borrow_mut().set_attr("__ty__", base_type);
|
||||||
with_obj_downcast_mut($name.clone(), |type_inst: &mut TypeInst| { type_inst.base.is_instantiated = true; });
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| { ty.base.is_instantiated = true; });
|
||||||
})*
|
})*
|
||||||
|
|
||||||
$({
|
$({
|
||||||
$(
|
$(
|
||||||
let vtable_name = stringify!($vtable_name);
|
let vtable_name = stringify!($vtable_name);
|
||||||
let vtable_value = $vtable_value;
|
let vtable_value = $vtable_value;
|
||||||
with_obj_downcast_mut($name.clone(), |type_inst: &mut TypeInst| {
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| {
|
||||||
type_inst.vtable.insert(vtable_name.to_string(), vtable_value);
|
ty.vtable.insert(vtable_name.to_string(), vtable_value);
|
||||||
});
|
});
|
||||||
)*
|
)*
|
||||||
})*
|
})*
|
||||||
@@ -115,82 +115,82 @@ pub fn init_types() {
|
|||||||
|
|
||||||
types! {
|
types! {
|
||||||
// base type
|
// base type
|
||||||
base_type: Type,
|
base_type: Ty,
|
||||||
// type definitions
|
// type definitions
|
||||||
Type {
|
Ty {
|
||||||
// Conversion methods
|
// Conversion methods
|
||||||
to_str => BuiltinFunctionInst::create("to_str", BaseObjInst::to_str, 1),
|
to_str => BuiltinFunction::create("to_str", BaseObj::to_str, 1),
|
||||||
to_repr => BuiltinFunctionInst::create("to_repr", BaseObjInst::to_repr, 1),
|
to_repr => BuiltinFunction::create("to_repr", BaseObj::to_repr, 1),
|
||||||
to_bool => BuiltinFunctionInst::create("to_bool", BaseObjInst::to_bool, 1),
|
to_bool => BuiltinFunction::create("to_bool", BaseObj::to_bool, 1),
|
||||||
to_int => BuiltinFunctionInst::create("to_int", BaseObjInst::not_implemented_un, 1),
|
to_int => BuiltinFunction::create("to_int", BaseObj::not_implemented_un, 1),
|
||||||
to_float => BuiltinFunctionInst::create("to_float", BaseObjInst::not_implemented_un, 1),
|
to_float => BuiltinFunction::create("to_float", BaseObj::not_implemented_un, 1),
|
||||||
len => BuiltinFunctionInst::create("len", BaseObjInst::not_implemented_un, 1),
|
len => BuiltinFunction::create("len", BaseObj::not_implemented_un, 1),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => BuiltinFunctionInst::create("__add__", BaseObjInst::not_implemented_bin, 2),
|
__add__ => BuiltinFunction::create("__add__", BaseObj::not_implemented_bin, 2),
|
||||||
__sub__ => BuiltinFunctionInst::create("__sub__", BaseObjInst::not_implemented_bin, 2),
|
__sub__ => BuiltinFunction::create("__sub__", BaseObj::not_implemented_bin, 2),
|
||||||
__mul__ => BuiltinFunctionInst::create("__mul__", BaseObjInst::not_implemented_bin, 2),
|
__mul__ => BuiltinFunction::create("__mul__", BaseObj::not_implemented_bin, 2),
|
||||||
__div__ => BuiltinFunctionInst::create("__div__", BaseObjInst::not_implemented_bin, 2),
|
__div__ => BuiltinFunction::create("__div__", BaseObj::not_implemented_bin, 2),
|
||||||
__and__ => BuiltinFunctionInst::create("__and__", BaseObjInst::and, 2),
|
__and__ => BuiltinFunction::create("__and__", BaseObj::and, 2),
|
||||||
__or__ => BuiltinFunctionInst::create("__or__", BaseObjInst::or, 2),
|
__or__ => BuiltinFunction::create("__or__", BaseObj::or, 2),
|
||||||
__ne__ => BuiltinFunctionInst::create("__ne__", BaseObjInst::ne, 2),
|
__ne__ => BuiltinFunction::create("__ne__", BaseObj::ne, 2),
|
||||||
__eq__ => BuiltinFunctionInst::create("__eq__", BaseObjInst::eq, 2),
|
__eq__ => BuiltinFunction::create("__eq__", BaseObj::eq, 2),
|
||||||
__gt__ => BuiltinFunctionInst::create("__gt__", BaseObjInst::not_implemented_bin, 2),
|
__gt__ => BuiltinFunction::create("__gt__", BaseObj::not_implemented_bin, 2),
|
||||||
__ge__ => BuiltinFunctionInst::create("__ge__", BaseObjInst::not_implemented_bin, 2),
|
__ge__ => BuiltinFunction::create("__ge__", BaseObj::not_implemented_bin, 2),
|
||||||
__lt__ => BuiltinFunctionInst::create("__lt__", BaseObjInst::not_implemented_bin, 2),
|
__lt__ => BuiltinFunction::create("__lt__", BaseObj::not_implemented_bin, 2),
|
||||||
__le__ => BuiltinFunctionInst::create("__le__", BaseObjInst::not_implemented_bin, 2),
|
__le__ => BuiltinFunction::create("__le__", BaseObj::not_implemented_bin, 2),
|
||||||
__pos__ => BuiltinFunctionInst::create("__pos__", BaseObjInst::not_implemented_un, 1),
|
__pos__ => BuiltinFunction::create("__pos__", BaseObj::not_implemented_un, 1),
|
||||||
__neg__ => BuiltinFunctionInst::create("__neg__", BaseObjInst::not_implemented_un, 1),
|
__neg__ => BuiltinFunction::create("__neg__", BaseObj::not_implemented_un, 1),
|
||||||
__not__ => BuiltinFunctionInst::create("__not__", BaseObjInst::not, 1),
|
__not__ => BuiltinFunction::create("__not__", BaseObj::not, 1),
|
||||||
},
|
},
|
||||||
Obj { },
|
Object { },
|
||||||
Str {
|
Str {
|
||||||
// Conversion methods
|
// Conversion methods
|
||||||
to_str => BuiltinFunctionInst::create("to_str", StrInst::to_str, 1),
|
to_str => BuiltinFunction::create("to_str", Str::to_str, 1),
|
||||||
to_repr => BuiltinFunctionInst::create("to_repr", StrInst::to_repr, 1),
|
to_repr => BuiltinFunction::create("to_repr", Str::to_repr, 1),
|
||||||
to_int => BuiltinFunctionInst::create("to_int", StrInst::to_int, 1),
|
to_int => BuiltinFunction::create("to_int", Str::to_int, 1),
|
||||||
to_float => BuiltinFunctionInst::create("to_float", StrInst::to_float, 1),
|
to_float => BuiltinFunction::create("to_float", Str::to_float, 1),
|
||||||
len => BuiltinFunctionInst::create("len", StrInst::len, 1),
|
len => BuiltinFunction::create("len", Str::len, 1),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => BuiltinFunctionInst::create("__add__", StrInst::add, 2),
|
__add__ => BuiltinFunction::create("__add__", Str::add, 2),
|
||||||
__mul__ => BuiltinFunctionInst::create("__mul__", StrInst::mul, 2),
|
__mul__ => BuiltinFunction::create("__mul__", Str::mul, 2),
|
||||||
// .lower, .upper, .slice, etc
|
// .lower, .upper, .slice, etc
|
||||||
},
|
},
|
||||||
Int {
|
Int {
|
||||||
// Conversion methods
|
// Conversion methods
|
||||||
to_int => BuiltinFunctionInst::create("to_int", IntInst::to_int, 1),
|
to_int => BuiltinFunction::create("to_int", Int::to_int, 1),
|
||||||
to_float => BuiltinFunctionInst::create("to_float", IntInst::to_float, 1),
|
to_float => BuiltinFunction::create("to_float", Int::to_float, 1),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => BuiltinFunctionInst::create("__add__", IntInst::add, 2),
|
__add__ => BuiltinFunction::create("__add__", Int::add, 2),
|
||||||
__sub__ => BuiltinFunctionInst::create("__sub__", IntInst::sub, 2),
|
__sub__ => BuiltinFunction::create("__sub__", Int::sub, 2),
|
||||||
__mul__ => BuiltinFunctionInst::create("__mul__", IntInst::mul, 2),
|
__mul__ => BuiltinFunction::create("__mul__", Int::mul, 2),
|
||||||
__div__ => BuiltinFunctionInst::create("__div__", IntInst::div, 2),
|
__div__ => BuiltinFunction::create("__div__", Int::div, 2),
|
||||||
//__eq__ => BuiltinFunctionInst::create("__eq__", IntInst::eq, 2),
|
//__eq__ => BuiltinFunction::create("__eq__", Int::eq, 2),
|
||||||
__gt__ => BuiltinFunctionInst::create("__gt__", IntInst::gt, 2),
|
__gt__ => BuiltinFunction::create("__gt__", Int::gt, 2),
|
||||||
__ge__ => BuiltinFunctionInst::create("__ge__", IntInst::ge, 2),
|
__ge__ => BuiltinFunction::create("__ge__", Int::ge, 2),
|
||||||
__lt__ => BuiltinFunctionInst::create("__lt__", IntInst::lt, 2),
|
__lt__ => BuiltinFunction::create("__lt__", Int::lt, 2),
|
||||||
__le__ => BuiltinFunctionInst::create("__le__", IntInst::le, 2),
|
__le__ => BuiltinFunction::create("__le__", Int::le, 2),
|
||||||
__pos__ => BuiltinFunctionInst::create("__pos__", IntInst::pos, 1),
|
__pos__ => BuiltinFunction::create("__pos__", Int::pos, 1),
|
||||||
__neg__ => BuiltinFunctionInst::create("__neg__", IntInst::neg, 1),
|
__neg__ => BuiltinFunction::create("__neg__", Int::neg, 1),
|
||||||
},
|
},
|
||||||
Float {
|
Float {
|
||||||
// Conversion methods
|
// Conversion methods
|
||||||
to_int => BuiltinFunctionInst::create("to_int", FloatInst::to_int, 1),
|
to_int => BuiltinFunction::create("to_int", Float::to_int, 1),
|
||||||
to_float => BuiltinFunctionInst::create("to_float", FloatInst::to_float, 1),
|
to_float => BuiltinFunction::create("to_float", Float::to_float, 1),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => BuiltinFunctionInst::create("__add__", FloatInst::add, 2),
|
__add__ => BuiltinFunction::create("__add__", Float::add, 2),
|
||||||
__sub__ => BuiltinFunctionInst::create("__sub__", FloatInst::sub, 2),
|
__sub__ => BuiltinFunction::create("__sub__", Float::sub, 2),
|
||||||
__mul__ => BuiltinFunctionInst::create("__mul__", FloatInst::mul, 2),
|
__mul__ => BuiltinFunction::create("__mul__", Float::mul, 2),
|
||||||
__div__ => BuiltinFunctionInst::create("__div__", FloatInst::div, 2),
|
__div__ => BuiltinFunction::create("__div__", Float::div, 2),
|
||||||
__gt__ => BuiltinFunctionInst::create("__gt__", FloatInst::gt, 2),
|
__gt__ => BuiltinFunction::create("__gt__", Float::gt, 2),
|
||||||
__ge__ => BuiltinFunctionInst::create("__ge__", FloatInst::ge, 2),
|
__ge__ => BuiltinFunction::create("__ge__", Float::ge, 2),
|
||||||
__lt__ => BuiltinFunctionInst::create("__lt__", FloatInst::lt, 2),
|
__lt__ => BuiltinFunction::create("__lt__", Float::lt, 2),
|
||||||
__le__ => BuiltinFunctionInst::create("__le__", FloatInst::le, 2),
|
__le__ => BuiltinFunction::create("__le__", Float::le, 2),
|
||||||
__pos__ => BuiltinFunctionInst::create("__pos__", FloatInst::pos, 1),
|
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
||||||
__neg__ => BuiltinFunctionInst::create("__neg__", FloatInst::neg, 1),
|
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
||||||
},
|
},
|
||||||
Bool { },
|
Bool { },
|
||||||
Nil { },
|
Nil { },
|
||||||
@@ -205,15 +205,15 @@ pub fn init_types() {
|
|||||||
///
|
///
|
||||||
/// I would implement this as a `From<T>` but it doesn't seem to work for a foreign type, and I'm
|
/// I would implement this as a `From<T>` but it doesn't seem to work for a foreign type, and I'm
|
||||||
/// not sure why.
|
/// not sure why.
|
||||||
pub fn make_ptr<T: Obj>(obj: T) -> ObjP {
|
pub fn make_ptr<T: Object>(obj: T) -> ObjP {
|
||||||
upcast_obj(Ptr::new(GcCell::new(obj)))
|
upcast_obj(Ptr::new(GcCell::new(obj)))
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Obj
|
// Object
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub trait Obj: Debug + Display + Any + Trace {
|
pub trait Object: Debug + Display + Any + Trace {
|
||||||
fn instantiate(&mut self);
|
fn instantiate(&mut self);
|
||||||
|
|
||||||
fn is_instantiated(&self) -> bool;
|
fn is_instantiated(&self) -> bool;
|
||||||
@@ -235,45 +235,42 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut type_inst = self.type_inst();
|
let mut ty = self.ty();
|
||||||
loop {
|
loop {
|
||||||
let vtable_entry =
|
let vtable_entry =
|
||||||
with_obj_downcast_mut(type_inst.clone(), |type_inst: &mut TypeInst| {
|
with_obj_downcast_mut(ty.clone(), |ty: &mut Ty| ty.vtable.get(name).cloned()).map(
|
||||||
type_inst.vtable.get(name).cloned()
|
|vtable_entry| {
|
||||||
})
|
let ptr = if obj_is_inst::<BuiltinFunction>(&vtable_entry)
|
||||||
.map(|vtable_entry| {
|
|| obj_is_inst::<UserFunction>(&vtable_entry)
|
||||||
let ptr = if obj_is_inst::<BuiltinFunctionInst>(&vtable_entry)
|
|
||||||
|| obj_is_inst::<UserFunctionInst>(&vtable_entry)
|
|
||||||
{
|
{
|
||||||
MethodInst::create(self_ptr.clone(), vtable_entry)
|
Method::create(self_ptr.clone(), vtable_entry)
|
||||||
} else {
|
} else {
|
||||||
vtable_entry
|
vtable_entry
|
||||||
};
|
};
|
||||||
// TODO Obj::get_attr - cache the vtable result somehow? we aren't caching for
|
// TODO Object::get_attr - cache the vtable result somehow? we aren't caching for
|
||||||
// speed, but rather so we don't have a million different method objects
|
// speed, but rather so we don't have a million different method objects
|
||||||
// floating around.
|
// floating around.
|
||||||
//self.set_attr(name, ptr.clone());
|
//self.set_attr(name, ptr.clone());
|
||||||
ptr
|
ptr
|
||||||
});
|
},
|
||||||
|
);
|
||||||
if vtable_entry.is_some() {
|
if vtable_entry.is_some() {
|
||||||
return vtable_entry;
|
return vtable_entry;
|
||||||
}
|
}
|
||||||
let type_inst_copy = type_inst.borrow().type_inst();
|
let ty_copy = ty.borrow().ty();
|
||||||
if type_inst.borrow().equals(&*type_inst_copy.borrow()) {
|
if ty.borrow().equals(&*ty_copy.borrow()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
type_inst = type_inst_copy;
|
ty = ty_copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_inst(&self) -> ObjP {
|
fn ty(&self) -> ObjP {
|
||||||
self.get_attr("__type__").expect("no __type__")
|
self.get_attr("__ty__").expect("no __ty__")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_name(&self) -> Rc<String> {
|
fn ty_name(&self) -> Rc<String> {
|
||||||
with_obj_downcast(self.type_inst(), |type_inst: &TypeInst| {
|
with_obj_downcast(self.ty(), |ty: &Ty| Rc::clone(&ty.name))
|
||||||
Rc::clone(&type_inst.name)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arity(&self) -> Option<Argc> {
|
fn arity(&self) -> Option<Argc> {
|
||||||
@@ -281,7 +278,7 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, _vm: &mut Vm, _argc: Argc) {
|
fn call(&self, _vm: &mut Vm, _argc: Argc) {
|
||||||
// TODO Obj::call - need to handle "this object cannot be called" errors
|
// TODO Object::call - need to handle "this object cannot be called" errors
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
todo!("Raise some kind of not implemented/not callable error for non-callable objects")
|
todo!("Raise some kind of not implemented/not callable error for non-callable objects")
|
||||||
}
|
}
|
||||||
@@ -290,7 +287,7 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool;
|
fn equals(&self, other: &dyn Object) -> bool;
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
@@ -298,16 +295,16 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BaseObjInst
|
// BaseObj
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Default, Debug, Trace, Finalize)]
|
#[derive(Default, Debug, Trace, Finalize)]
|
||||||
pub(crate) struct BaseObjInst {
|
pub(crate) struct BaseObj {
|
||||||
attrs: Attrs,
|
attrs: Attrs,
|
||||||
is_instantiated: bool,
|
is_instantiated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for BaseObjInst {
|
impl Clone for BaseObj {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
attrs: self.attrs.clone(),
|
attrs: self.attrs.clone(),
|
||||||
@@ -316,13 +313,13 @@ impl Clone for BaseObjInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BaseObjInst {
|
impl Display for BaseObj {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "<BaseObjInst at {:x}>", (self as *const _ as usize))
|
write!(fmt, "<BaseObj at {:x}>", (self as *const _ as usize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for BaseObjInst {
|
impl Object for BaseObj {
|
||||||
fn instantiate(&mut self) {
|
fn instantiate(&mut self) {
|
||||||
self.is_instantiated = true;
|
self.is_instantiated = true;
|
||||||
}
|
}
|
||||||
@@ -339,8 +336,8 @@ impl Obj for BaseObjInst {
|
|||||||
&mut self.attrs
|
&mut self.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<BaseObjInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<BaseObj>() {
|
||||||
// compare all attrs
|
// compare all attrs
|
||||||
self.attrs.iter().all(|(k1, v1)| {
|
self.attrs.iter().all(|(k1, v1)| {
|
||||||
other
|
other
|
||||||
@@ -364,15 +361,15 @@ impl Obj for BaseObjInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// ObjInst
|
// Obj
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct ObjInst {
|
pub struct Obj {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjInst {
|
impl Obj {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
@@ -382,37 +379,37 @@ impl ObjInst {
|
|||||||
impl_create!();
|
impl_create!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ObjInst {
|
impl Display for Obj {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "<ObjInst at {:x}>", (self as *const _ as usize))
|
write!(fmt, "<Obj at {:x}>", (self as *const _ as usize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for ObjInst {
|
impl Object for Obj {
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<ObjInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Obj>() {
|
||||||
self.base.equals(&other.base)
|
self.base.equals(&other.base)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!(Obj);
|
impl_base_obj!(Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// TypeInst
|
// Ty
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Trace, Finalize)]
|
#[derive(Trace, Finalize)]
|
||||||
pub struct TypeInst {
|
pub struct Ty {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
name: Rc<String>,
|
name: Rc<String>,
|
||||||
vtable: HashMap<String, ObjP>,
|
vtable: HashMap<String, ObjP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInst {
|
impl Ty {
|
||||||
pub fn new(name: impl ToString) -> Self {
|
pub fn new(name: impl ToString) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Rc::new(name.to_string()),
|
name: Rc::new(name.to_string()),
|
||||||
@@ -428,35 +425,35 @@ impl TypeInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for TypeInst {
|
impl Debug for Ty {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"<Type {} at {:x}>",
|
"<Ty {} at {:x}>",
|
||||||
self.name,
|
self.name,
|
||||||
(self as *const _ as usize)
|
(self as *const _ as usize)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TypeInst {
|
impl Display for Ty {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
"<Type {} at {:x}>",
|
"<Ty {} at {:x}>",
|
||||||
self.name,
|
self.name,
|
||||||
(self as *const _ as usize)
|
(self as *const _ as usize)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for TypeInst {
|
impl Object for Ty {
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<TypeInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Ty>() {
|
||||||
// TODO TypeInst::equals : something more robust than this
|
// TODO Ty::equals : something more robust than this
|
||||||
// Types should hold equality if they have the same name
|
// Tys should hold equality if they have the same name
|
||||||
// the problem is that Type.get_attr("__type__") is going to return itself, so we have
|
// the problem is that Ty.get_attr("__ty__") is going to return itself, so we have
|
||||||
// to go through attributes to specially exclude to the __type__ attribute if it points
|
// to go through attributes to specially exclude to the __ty__ attribute if it points
|
||||||
// to ourself.
|
// to ourself.
|
||||||
// How do we detect that it's pointing to ourself? I suppose pointers are the way
|
// How do we detect that it's pointing to ourself? I suppose pointers are the way
|
||||||
self.name == other.name
|
self.name == other.name
|
||||||
@@ -465,21 +462,21 @@ impl Obj for TypeInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!(Type);
|
impl_base_obj!(Ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// StrInst
|
// Str
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct StrInst {
|
pub struct Str {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
str_value: Rc<String>,
|
str_value: Rc<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StrInst {
|
impl Str {
|
||||||
pub fn new(str_value: impl ToString) -> Self {
|
pub fn new(str_value: impl ToString) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
@@ -494,19 +491,19 @@ impl StrInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for StrInst {
|
impl Display for Str {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", self.str_value)
|
write!(fmt, "{}", self.str_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for StrInst {
|
impl Object for Str {
|
||||||
fn is_truthy(&self) -> bool {
|
fn is_truthy(&self) -> bool {
|
||||||
!self.str_value.is_empty()
|
!self.str_value.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<StrInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Str>() {
|
||||||
self.str_value == other.str_value
|
self.str_value == other.str_value
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -517,16 +514,16 @@ impl Obj for StrInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// IntInst
|
// Int
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct IntInst {
|
pub struct Int {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
int_value: i64,
|
int_value: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntInst {
|
impl Int {
|
||||||
pub fn new(int_value: i64) -> Self {
|
pub fn new(int_value: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
int_value,
|
int_value,
|
||||||
@@ -541,21 +538,21 @@ impl IntInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IntInst {
|
impl Display for Int {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", self.int_value)
|
write!(fmt, "{}", self.int_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for IntInst {
|
impl Object for Int {
|
||||||
fn is_truthy(&self) -> bool {
|
fn is_truthy(&self) -> bool {
|
||||||
self.int_value != 0
|
self.int_value != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<IntInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Int>() {
|
||||||
self.int_value == other.int_value
|
self.int_value == other.int_value
|
||||||
} else if let Some(other) = other.as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(other) = other.as_any().downcast_ref::<Float>() {
|
||||||
self.int_value as f64 == other.float_value
|
self.int_value as f64 == other.float_value
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -566,16 +563,16 @@ impl Obj for IntInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// FloatInst
|
// Float
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct FloatInst {
|
pub struct Float {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
float_value: f64,
|
float_value: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatInst {
|
impl Float {
|
||||||
pub fn new(float_value: f64) -> Self {
|
pub fn new(float_value: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
float_value,
|
float_value,
|
||||||
@@ -590,7 +587,7 @@ impl FloatInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for FloatInst {
|
impl Display for Float {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// we want to force the .0 if it's a whole number
|
// we want to force the .0 if it's a whole number
|
||||||
if self.float_value == self.float_value.floor() {
|
if self.float_value == self.float_value.floor() {
|
||||||
@@ -601,15 +598,15 @@ impl Display for FloatInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for FloatInst {
|
impl Object for Float {
|
||||||
fn is_truthy(&self) -> bool {
|
fn is_truthy(&self) -> bool {
|
||||||
self.float_value != 0.0
|
self.float_value != 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<FloatInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Float>() {
|
||||||
self.float_value == other.float_value
|
self.float_value == other.float_value
|
||||||
} else if let Some(other) = other.as_any().downcast_ref::<IntInst>() {
|
} else if let Some(other) = other.as_any().downcast_ref::<Int>() {
|
||||||
self.float_value == other.int_value as f64
|
self.float_value == other.int_value as f64
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -620,16 +617,16 @@ impl Obj for FloatInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BoolInst
|
// Bool
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct BoolInst {
|
pub struct Bool {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
bool_value: bool,
|
bool_value: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoolInst {
|
impl Bool {
|
||||||
pub fn new(bool_value: bool) -> Self {
|
pub fn new(bool_value: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bool_value,
|
bool_value,
|
||||||
@@ -644,19 +641,19 @@ impl BoolInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BoolInst {
|
impl Display for Bool {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", self.bool_value)
|
write!(fmt, "{}", self.bool_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for BoolInst {
|
impl Object for Bool {
|
||||||
fn is_truthy(&self) -> bool {
|
fn is_truthy(&self) -> bool {
|
||||||
self.bool_value
|
self.bool_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<BoolInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Bool>() {
|
||||||
self.bool_value == other.bool_value
|
self.bool_value == other.bool_value
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -667,15 +664,15 @@ impl Obj for BoolInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// NilInst
|
// Nil
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Default, Trace, Finalize)]
|
#[derive(Debug, Default, Trace, Finalize)]
|
||||||
pub struct NilInst {
|
pub struct Nil {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NilInst {
|
impl Nil {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
@@ -683,19 +680,19 @@ impl NilInst {
|
|||||||
impl_create!();
|
impl_create!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for NilInst {
|
impl Display for Nil {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "nil")
|
write!(fmt, "nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for NilInst {
|
impl Object for Nil {
|
||||||
fn is_truthy(&self) -> bool {
|
fn is_truthy(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
other.as_any().downcast_ref::<NilInst>().is_some()
|
other.as_any().downcast_ref::<Nil>().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!(Nil);
|
impl_base_obj!(Nil);
|
||||||
@@ -709,49 +706,49 @@ impl Obj for NilInst {
|
|||||||
fn test_new_objects() {
|
fn test_new_objects() {
|
||||||
init_types();
|
init_types();
|
||||||
|
|
||||||
let type_value = TypeInst::create("Type");
|
let type_value = Ty::create("Ty");
|
||||||
assert_eq!(&*type_value.borrow().type_name(), "Type");
|
assert_eq!(&*type_value.borrow().ty_name(), "Ty");
|
||||||
|
|
||||||
let str_value = StrInst::create("asdfasdfasdfasdfasdf");
|
let str_value = Str::create("asdfasdfasdfasdfasdf");
|
||||||
assert_eq!(&*str_value.borrow().type_name(), "Str");
|
assert_eq!(&*str_value.borrow().ty_name(), "Str");
|
||||||
|
|
||||||
let int_value = IntInst::create(1234);
|
let int_value = Int::create(1234);
|
||||||
assert_eq!(&*int_value.borrow().type_name(), "Int");
|
assert_eq!(&*int_value.borrow().ty_name(), "Int");
|
||||||
|
|
||||||
let float_value = FloatInst::create(1234.5678);
|
let float_value = Float::create(1234.5678);
|
||||||
assert_eq!(&*float_value.borrow().type_name(), "Float");
|
assert_eq!(&*float_value.borrow().ty_name(), "Float");
|
||||||
|
|
||||||
let nil_value = NilInst::create();
|
let nil_value = Nil::create();
|
||||||
assert_eq!(&*nil_value.borrow().type_name(), "Nil");
|
assert_eq!(&*nil_value.borrow().ty_name(), "Nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_obj_equals() {
|
fn test_obj_equals() {
|
||||||
init_types();
|
init_types();
|
||||||
|
|
||||||
let int1 = IntInst::create(1234);
|
let int1 = Int::create(1234);
|
||||||
let int2 = IntInst::create(1234);
|
let int2 = Int::create(1234);
|
||||||
|
|
||||||
assert!(int1.borrow().equals(&*int2.borrow()));
|
assert!(int1.borrow().equals(&*int2.borrow()));
|
||||||
assert!(int2.borrow().equals(&*int1.borrow()));
|
assert!(int2.borrow().equals(&*int1.borrow()));
|
||||||
|
|
||||||
let float1 = FloatInst::create(1234.0);
|
let float1 = Float::create(1234.0);
|
||||||
assert!(int1.borrow().equals(&*float1.borrow()));
|
assert!(int1.borrow().equals(&*float1.borrow()));
|
||||||
assert!(float1.borrow().equals(&*int2.borrow()));
|
assert!(float1.borrow().equals(&*int2.borrow()));
|
||||||
|
|
||||||
// self-equality
|
// self-equality
|
||||||
let str1 = StrInst::create("1234");
|
let str1 = Str::create("1234");
|
||||||
assert!(str1.borrow().equals(&*str1.borrow()));
|
assert!(str1.borrow().equals(&*str1.borrow()));
|
||||||
|
|
||||||
let str2 = StrInst::create("1234");
|
let str2 = Str::create("1234");
|
||||||
assert!(str1.borrow().equals(&*str2.borrow()));
|
assert!(str1.borrow().equals(&*str2.borrow()));
|
||||||
assert!(str2.borrow().equals(&*str1.borrow()));
|
assert!(str2.borrow().equals(&*str1.borrow()));
|
||||||
|
|
||||||
assert!(!str1.borrow().equals(&*float1.borrow()));
|
assert!(!str1.borrow().equals(&*float1.borrow()));
|
||||||
assert!(!str1.borrow().equals(&*int1.borrow()));
|
assert!(!str1.borrow().equals(&*int1.borrow()));
|
||||||
|
|
||||||
let obj1 = ObjInst::create();
|
let obj1 = Obj::create();
|
||||||
let obj2 = ObjInst::create();
|
let obj2 = Obj::create();
|
||||||
assert!(obj1.borrow().equals(&*obj2.borrow()));
|
assert!(obj1.borrow().equals(&*obj2.borrow()));
|
||||||
|
|
||||||
// these objects aren't equal anymore
|
// these objects aren't equal anymore
|
||||||
@@ -766,14 +763,14 @@ fn test_obj_equals() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_obj_vtable() {
|
fn test_obj_vtable() {
|
||||||
init_types();
|
init_types();
|
||||||
let str1 = StrInst::create("asdfasdfasdf");
|
let str1 = Str::create("asdfasdfasdf");
|
||||||
|
|
||||||
let to_string_ptr = str1.borrow_mut().get_vtable_attr(str1.clone(), "to_str");
|
let to_string_ptr = str1.borrow_mut().get_vtable_attr(str1.clone(), "to_str");
|
||||||
assert!(to_string_ptr.is_some());
|
assert!(to_string_ptr.is_some());
|
||||||
|
|
||||||
let to_string_ptr = to_string_ptr.unwrap();
|
let to_string_ptr = to_string_ptr.unwrap();
|
||||||
assert!(obj_is_inst::<MethodInst>(&to_string_ptr));
|
assert!(obj_is_inst::<Method>(&to_string_ptr));
|
||||||
with_obj_downcast(to_string_ptr.clone(), |method: &MethodInst| {
|
with_obj_downcast(to_string_ptr.clone(), |method: &Method| {
|
||||||
assert!(method.self_binding().borrow().equals(&*str1.borrow()));
|
assert!(method.self_binding().borrow().equals(&*str1.borrow()));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -785,8 +782,8 @@ fn test_obj_vtable() {
|
|||||||
|
|
||||||
// this is like doing "asdfasdfasdf".to_string().to_string()
|
// this is like doing "asdfasdfasdf".to_string().to_string()
|
||||||
let method_to_string_ptr = method_to_string_ptr.unwrap();
|
let method_to_string_ptr = method_to_string_ptr.unwrap();
|
||||||
assert!(obj_is_inst::<MethodInst>(&method_to_string_ptr));
|
assert!(obj_is_inst::<Method>(&method_to_string_ptr));
|
||||||
with_obj_downcast(method_to_string_ptr.clone(), |method: &MethodInst| {
|
with_obj_downcast(method_to_string_ptr.clone(), |method: &Method| {
|
||||||
assert!(method
|
assert!(method
|
||||||
.self_binding()
|
.self_binding()
|
||||||
.borrow()
|
.borrow()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::rc::Rc;
|
|||||||
use gc::{Finalize, Trace};
|
use gc::{Finalize, Trace};
|
||||||
|
|
||||||
use crate::obj::macros::*;
|
use crate::obj::macros::*;
|
||||||
use crate::obj::{make_ptr, BaseObjInst, Obj, ObjP};
|
use crate::obj::{make_ptr, BaseObj, ObjP, Object};
|
||||||
use crate::vm::{Argc, Chunk, Frame, Function, Vm};
|
use crate::vm::{Argc, Chunk, Frame, Function, Vm};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -49,14 +49,14 @@ pub enum FunctionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BuiltinFunctionInst
|
// BuiltinFunction
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub type BuiltinFunctionPtr = fn(vm: &mut Vm, function_state: FunctionState) -> FunctionResult;
|
pub type BuiltinFunctionPtr = fn(vm: &mut Vm, function_state: FunctionState) -> FunctionResult;
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
#[derive(Debug, Trace, Finalize)]
|
||||||
pub struct BuiltinFunctionInst {
|
pub struct BuiltinFunction {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
name: Rc<String>,
|
name: Rc<String>,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
@@ -64,7 +64,7 @@ pub struct BuiltinFunctionInst {
|
|||||||
arity: Argc,
|
arity: Argc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltinFunctionInst {
|
impl BuiltinFunction {
|
||||||
pub fn new(name: impl ToString, function: BuiltinFunctionPtr, arity: Argc) -> Self {
|
pub fn new(name: impl ToString, function: BuiltinFunctionPtr, arity: Argc) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
@@ -85,7 +85,7 @@ impl BuiltinFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BuiltinFunctionInst {
|
impl Display for BuiltinFunction {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
@@ -97,7 +97,7 @@ impl Display for BuiltinFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for BuiltinFunctionInst {
|
impl Object for BuiltinFunction {
|
||||||
fn arity(&self) -> Option<Argc> {
|
fn arity(&self) -> Option<Argc> {
|
||||||
Some(self.arity)
|
Some(self.arity)
|
||||||
}
|
}
|
||||||
@@ -111,10 +111,10 @@ impl Obj for BuiltinFunctionInst {
|
|||||||
vm.push_frame(new_frame);
|
vm.push_frame(new_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
// TODO BuiltinFunctionInst::equals : need something more robust than checking addr_eq,
|
// TODO BuiltinFunction::equals : need something more robust than checking addr_eq,
|
||||||
// maybe check the self_binding pointer too?
|
// maybe check the self_binding pointer too?
|
||||||
if let Some(other) = other.as_any().downcast_ref::<BuiltinFunctionInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<BuiltinFunction>() {
|
||||||
ptr::addr_eq(self, other)
|
ptr::addr_eq(self, other)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -125,12 +125,12 @@ impl Obj for BuiltinFunctionInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// UserFunctionInst
|
// UserFunction
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Clone, Trace, Finalize)]
|
#[derive(Debug, Clone, Trace, Finalize)]
|
||||||
pub struct UserFunctionInst {
|
pub struct UserFunction {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
name: Rc<String>,
|
name: Rc<String>,
|
||||||
#[unsafe_ignore_trace]
|
#[unsafe_ignore_trace]
|
||||||
@@ -139,7 +139,7 @@ pub struct UserFunctionInst {
|
|||||||
captures: Vec<ObjP>,
|
captures: Vec<ObjP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserFunctionInst {
|
impl UserFunction {
|
||||||
pub fn new(chunk: Chunk, arity: Argc) -> Self {
|
pub fn new(chunk: Chunk, arity: Argc) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
@@ -169,7 +169,7 @@ impl UserFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for UserFunctionInst {
|
impl Display for UserFunction {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
@@ -181,7 +181,7 @@ impl Display for UserFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for UserFunctionInst {
|
impl Object for UserFunction {
|
||||||
fn arity(&self) -> Option<Argc> {
|
fn arity(&self) -> Option<Argc> {
|
||||||
Some(self.arity)
|
Some(self.arity)
|
||||||
}
|
}
|
||||||
@@ -199,9 +199,9 @@ impl Obj for UserFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<UserFunctionInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<UserFunction>() {
|
||||||
// TODO UserFunctionInst::equals : need something more robust than checking addr_eq.
|
// TODO UserFunction::equals : need something more robust than checking addr_eq.
|
||||||
ptr::addr_eq(self, other)
|
ptr::addr_eq(self, other)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -212,19 +212,19 @@ impl Obj for UserFunctionInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// MethodInst
|
// Method
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Trace, Finalize)]
|
#[derive(Trace, Finalize)]
|
||||||
pub struct MethodInst {
|
pub struct Method {
|
||||||
base: BaseObjInst,
|
base: BaseObj,
|
||||||
self_binding: ObjP,
|
self_binding: ObjP,
|
||||||
function: ObjP,
|
function: ObjP,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for MethodInst {
|
impl Debug for Method {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("MethodInst")
|
fmt.debug_struct("Method")
|
||||||
.field("base", &self.base)
|
.field("base", &self.base)
|
||||||
.field("self_binding", &format!("{}", self.self_binding.borrow()))
|
.field("self_binding", &format!("{}", self.self_binding.borrow()))
|
||||||
.field("function", &self.function)
|
.field("function", &self.function)
|
||||||
@@ -232,7 +232,7 @@ impl Debug for MethodInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MethodInst {
|
impl Method {
|
||||||
pub fn new(self_binding: ObjP, function: ObjP) -> Self {
|
pub fn new(self_binding: ObjP, function: ObjP) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
@@ -252,13 +252,13 @@ impl MethodInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for MethodInst {
|
impl Display for Method {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "{}", self.function.borrow())
|
write!(fmt, "{}", self.function.borrow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for MethodInst {
|
impl Object for Method {
|
||||||
fn arity(&self) -> Option<Argc> {
|
fn arity(&self) -> Option<Argc> {
|
||||||
// Subtract one from the arity - this is because the VM uses arity() to check against the
|
// Subtract one from the arity - this is because the VM uses arity() to check against the
|
||||||
// number of arguments passed.
|
// number of arguments passed.
|
||||||
@@ -273,8 +273,8 @@ impl Obj for MethodInst {
|
|||||||
self.function.borrow().call(vm, argc)
|
self.function.borrow().call(vm, argc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Object) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<MethodInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<Method>() {
|
||||||
ptr::addr_eq(&*self.self_binding, &*other.self_binding)
|
ptr::addr_eq(&*self.self_binding, &*other.self_binding)
|
||||||
&& ptr::addr_eq(&*self.function, &*other.function)
|
&& ptr::addr_eq(&*self.function, &*other.function)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ macro_rules! impl_base_obj {
|
|||||||
.expect(concat!("no ", stringify!($type_name)))
|
.expect(concat!("no ", stringify!($type_name)))
|
||||||
.clone()
|
.clone()
|
||||||
});
|
});
|
||||||
self.set_attr("__type__", ty);
|
self.set_attr("__ty__", ty);
|
||||||
self.$base_name.instantiate();
|
self.$base_name.instantiate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/vm.rs
11
src/vm.rs
@@ -98,7 +98,7 @@ impl Vm {
|
|||||||
/// Create a new virtual machine with the given chunk, constants, and global names.
|
/// Create a new virtual machine with the given chunk, constants, and global names.
|
||||||
pub fn new(chunk: Rc<Chunk>, constants: Vec<ObjP>, global_names: Vec<String>) -> Self {
|
pub fn new(chunk: Rc<Chunk>, constants: Vec<ObjP>, global_names: Vec<String>) -> Self {
|
||||||
// set up globals
|
// set up globals
|
||||||
let nil = NilInst::create();
|
let nil = Nil::create();
|
||||||
let mut globals: Vec<_> = global_names.iter().map(|_| ObjP::clone(&nil)).collect();
|
let mut globals: Vec<_> = global_names.iter().map(|_| ObjP::clone(&nil)).collect();
|
||||||
|
|
||||||
let mut register_global = |name: &str, value: ObjP| {
|
let mut register_global = |name: &str, value: ObjP| {
|
||||||
@@ -290,7 +290,7 @@ impl Vm {
|
|||||||
// need both declarations to borrow cell value
|
// need both declarations to borrow cell value
|
||||||
let name_obj = Ptr::clone(&self.constants[constant_id as usize]);
|
let name_obj = Ptr::clone(&self.constants[constant_id as usize]);
|
||||||
let name =
|
let name =
|
||||||
with_obj_downcast(name_obj, |name: &StrInst| Rc::clone(&name.str_value()));
|
with_obj_downcast(name_obj, |name: &Str| Rc::clone(&name.str_value()));
|
||||||
let owner = self.pop();
|
let owner = self.pop();
|
||||||
let value = owner.borrow_mut().get_vtable_attr(owner.clone(), &name);
|
let value = owner.borrow_mut().get_vtable_attr(owner.clone(), &name);
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
@@ -309,7 +309,7 @@ impl Vm {
|
|||||||
Op::SetAttr(constant_id) => {
|
Op::SetAttr(constant_id) => {
|
||||||
let name_obj = Ptr::clone(&self.constants[constant_id as usize]);
|
let name_obj = Ptr::clone(&self.constants[constant_id as usize]);
|
||||||
let name =
|
let name =
|
||||||
with_obj_downcast(name_obj, |name: &StrInst| Rc::clone(&name.str_value()));
|
with_obj_downcast(name_obj, |name: &Str| Rc::clone(&name.str_value()));
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
let target = self.pop();
|
let target = self.pop();
|
||||||
|
|
||||||
@@ -378,10 +378,9 @@ impl Vm {
|
|||||||
// constants, we want to deep-clone this object so we don't alter any live
|
// constants, we want to deep-clone this object so we don't alter any live
|
||||||
// objects.
|
// objects.
|
||||||
// there is some room for optimization here so we aren't cloning the entire
|
// there is some room for optimization here so we aren't cloning the entire
|
||||||
// UserFunctionInst for every individual capture in a function.
|
// UserFunction for every individual capture in a function.
|
||||||
let fun_ptr = self.pop();
|
let fun_ptr = self.pop();
|
||||||
let mut fun: UserFunctionInst =
|
let mut fun: UserFunction = with_obj_downcast(fun_ptr, UserFunction::clone);
|
||||||
with_obj_downcast(fun_ptr, UserFunctionInst::clone);
|
|
||||||
let frame_index = self.frames.len() - (depth as usize) - 1;
|
let frame_index = self.frames.len() - (depth as usize) - 1;
|
||||||
let stack_base = self.frames[frame_index].stack_base;
|
let stack_base = self.frames[frame_index].stack_base;
|
||||||
let value = Ptr::clone(&self.stack[stack_base + (slot as usize)]);
|
let value = Ptr::clone(&self.stack[stack_base + (slot as usize)]);
|
||||||
|
|||||||
Reference in New Issue
Block a user