2024-09-30 15:15:41 -07:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::fmt::{self, Debug, Display};
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
|
|
use gc::{Finalize, Trace};
|
|
|
|
|
|
|
|
|
|
use crate::obj::macros::*;
|
|
|
|
|
use crate::obj::prelude::*;
|
|
|
|
|
use crate::obj::{BaseObj, BUILTINS};
|
|
|
|
|
use crate::vm::{Argc, Vm};
|
|
|
|
|
|
|
|
|
|
#[derive(Trace, Finalize)]
|
|
|
|
|
pub struct Ty {
|
|
|
|
|
base: BaseObj,
|
|
|
|
|
#[unsafe_ignore_trace]
|
|
|
|
|
name: Rc<String>,
|
|
|
|
|
vtable: HashMap<String, ObjP>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Ty {
|
|
|
|
|
pub fn new(name: impl ToString) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
name: Rc::new(name.to_string()),
|
|
|
|
|
base: Default::default(),
|
|
|
|
|
vtable: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn name(&self) -> &Rc<String> {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn vtable(&self) -> &HashMap<String, ObjP> {
|
|
|
|
|
&self.vtable
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_create!(name: impl ToString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for Ty {
|
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
write!(
|
|
|
|
|
fmt,
|
|
|
|
|
"<Ty {} at {:#x}>",
|
|
|
|
|
self.name,
|
|
|
|
|
(self as *const _ as usize)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for Ty {
|
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
Debug::fmt(self, fmt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Object for Ty {
|
|
|
|
|
fn equals(&self, other: &dyn Object) -> bool {
|
|
|
|
|
if let Some(other) = other.as_any().downcast_ref::<Ty>() {
|
|
|
|
|
// TODO Ty::equals : something more robust than this
|
|
|
|
|
// Tys should hold equality if they have the same name
|
|
|
|
|
// 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 __ty__ attribute if it points
|
|
|
|
|
// to ourself.
|
|
|
|
|
// How do we detect that it's pointing to ourself? I suppose pointers are the way
|
|
|
|
|
self.name == other.name
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn call(&self, vm: &mut Vm, argc: Argc) {
|
|
|
|
|
// TODO Object::call - need to handle "this object cannot be called" errors
|
|
|
|
|
// BLOCKED-ON: exceptions
|
|
|
|
|
|
|
|
|
|
// I don't think there's any way we could call this *without* it being a method.
|
|
|
|
|
// If you do e.g. `Int.__call__`, Int is an object, so it should be doing `__call__` as a
|
|
|
|
|
// vtable value.
|
|
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) {
|
|
|
|
|
let index = vm.stack().len() - 1 - argc as usize;
|
|
|
|
|
let this = vm.stack()[index].clone();
|
|
|
|
|
assert!(
|
|
|
|
|
std::ptr::addr_eq(&*this.borrow(), self),
|
|
|
|
|
"calling {}.__call__ on type that is not ourselves",
|
|
|
|
|
self.ty_name()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let function = self
|
|
|
|
|
.vtable
|
|
|
|
|
.get("__call__")
|
|
|
|
|
.expect("Why does a type not have a __call__ member?");
|
|
|
|
|
function.borrow().call(vm, argc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn arity(&self) -> Option<Argc> {
|
|
|
|
|
// HACK XXX NOTE Ty __call__ arity :
|
|
|
|
|
// We need to tread carefully here. Normally, `__call__` would be wrapped as a method.
|
|
|
|
|
// However, we have to get the `__call__` member directly from the vtable.
|
|
|
|
|
// We are subtracting 1 from the arity, because whenever it *does* become a method, the
|
|
|
|
|
// arity will match when we call `Ty` directly.
|
|
|
|
|
self.vtable
|
|
|
|
|
.get("__call__")
|
|
|
|
|
.and_then(|function| function.borrow().arity())
|
|
|
|
|
.map(|n| n - 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_base_obj!(Ty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn init_types() {
|
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
macro_rules! types {
|
|
|
|
|
(
|
|
|
|
|
base_type: $base_type:ident,
|
|
|
|
|
$(
|
|
|
|
|
$name:ident {
|
|
|
|
|
$( $vtable_name:ident => $vtable_value:expr ),* $(,)?
|
|
|
|
|
}
|
|
|
|
|
),* $(,)?
|
|
|
|
|
) => {{
|
|
|
|
|
$(
|
|
|
|
|
let $name = make_ptr(Ty::new(stringify!($name)));
|
|
|
|
|
BUILTINS.with_borrow_mut(|builtins| builtins.insert(stringify!($name).to_string(), $name.clone()));
|
|
|
|
|
)*
|
|
|
|
|
|
|
|
|
|
// We have to instantiate these objects all by hand. This is because the `instantiate`
|
|
|
|
|
// function does some stuff that may accidentally cause infinite recursion while we are
|
|
|
|
|
// setting up these fundamental types.
|
|
|
|
|
$({
|
|
|
|
|
let base_type = $base_type.clone();
|
|
|
|
|
$name.borrow_mut().set_attr("__ty__", base_type);
|
|
|
|
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| { ty.base.is_instantiated = true; });
|
|
|
|
|
})*
|
|
|
|
|
|
|
|
|
|
$({
|
|
|
|
|
$(
|
|
|
|
|
let vtable_name = stringify!($vtable_name);
|
|
|
|
|
let vtable_value = $vtable_value;
|
|
|
|
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| {
|
|
|
|
|
ty.vtable.insert(vtable_name.to_string(), vtable_value);
|
|
|
|
|
});
|
|
|
|
|
)*
|
|
|
|
|
})*
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
types! {
|
|
|
|
|
// base type
|
|
|
|
|
base_type: Ty,
|
|
|
|
|
// type definitions
|
|
|
|
|
Ty {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_str => BuiltinFunction::create("to_str", BaseObj::to_str, 1),
|
|
|
|
|
to_repr => BuiltinFunction::create("to_repr", BaseObj::to_repr, 1),
|
|
|
|
|
to_bool => BuiltinFunction::create("to_bool", BaseObj::to_bool, 1),
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", BaseObj::not_implemented_un, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", BaseObj::not_implemented_un, 1),
|
2024-09-30 16:49:48 -07:00
|
|
|
to_list => BuiltinFunction::create("to_list", BaseObj::not_implemented_un, 1),
|
2024-09-30 15:15:41 -07:00
|
|
|
len => BuiltinFunction::create("len", BaseObj::not_implemented_un, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
// TODO Ty::do_call, Ty::init - implement these methods
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", BaseObj::not_implemented_un, 1),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", BaseObj::not_implemented_un, 1),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__and__ => BuiltinFunction::create("__and__", BaseObj::and, 2),
|
|
|
|
|
__or__ => BuiltinFunction::create("__or__", BaseObj::or, 2),
|
|
|
|
|
__ne__ => BuiltinFunction::create("__ne__", BaseObj::ne, 2),
|
|
|
|
|
__eq__ => BuiltinFunction::create("__eq__", BaseObj::eq, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", BaseObj::not_implemented_bin, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", BaseObj::not_implemented_un, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", BaseObj::not_implemented_un, 1),
|
|
|
|
|
__not__ => BuiltinFunction::create("__not__", BaseObj::not, 1),
|
|
|
|
|
},
|
|
|
|
|
Obj {
|
|
|
|
|
//__call__ => BuiltinFunction::create("__call__",
|
|
|
|
|
},
|
2024-09-30 16:33:58 -07:00
|
|
|
List {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_repr => BuiltinFunction::create("to_repr", List::to_repr, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", List::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", List::init, 2),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__index__ => BuiltinFunction::create("__index__", List::index, 2),
|
|
|
|
|
|
|
|
|
|
// Methods
|
|
|
|
|
push => BuiltinFunction::create("push", List::push, 2),
|
|
|
|
|
pop => BuiltinFunction::create("pop", List::pop, 1),
|
|
|
|
|
},
|
2024-09-30 15:15:41 -07:00
|
|
|
Str {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_str => BuiltinFunction::create("to_str", Str::to_str, 1),
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Str::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Str::to_float, 1),
|
2024-09-30 16:49:48 -07:00
|
|
|
to_list => BuiltinFunction::create("to_list", Str::to_list, 1),
|
2024-09-30 15:15:41 -07:00
|
|
|
len => BuiltinFunction::create("len", Str::len, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Str::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Str::init, 2),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Str::add, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Str::mul, 2),
|
2024-09-30 16:33:58 -07:00
|
|
|
|
2024-09-30 16:49:48 -07:00
|
|
|
__index__ => BuiltinFunction::create("__index__", Str::index, 2),
|
|
|
|
|
|
2024-09-30 16:33:58 -07:00
|
|
|
// Methods
|
|
|
|
|
// TODO Str methods - .lower, .upper, .slice, etc
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Int {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Int::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Int::to_float, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Int::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Int::init, 2),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Int::add, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", Int::sub, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Int::mul, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", Int::div, 2),
|
|
|
|
|
//__eq__ => BuiltinFunction::create("__eq__", Int::eq, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", Int::gt, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", Int::ge, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", Int::lt, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", Int::le, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", Int::pos, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", Int::neg, 1),
|
|
|
|
|
},
|
|
|
|
|
Float {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Float::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Float::to_float, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Float::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Float::init, 2),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Float::add, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", Float::sub, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Float::mul, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", Float::div, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", Float::gt, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", Float::ge, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", Float::lt, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", Float::le, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
|
|
|
|
},
|
|
|
|
|
Bool {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Bool::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Bool::to_float, 1),
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Bool::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Bool::init, 2),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
},
|
|
|
|
|
Nil {
|
|
|
|
|
// Conversion methods
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Nil::do_call, 1),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Nil::init, 1),
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
},
|
|
|
|
|
BuiltinFunction { },
|
|
|
|
|
UserFunction { },
|
|
|
|
|
Method { },
|
|
|
|
|
}
|
|
|
|
|
}
|