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, vtable: HashMap, } 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 { &self.name } pub fn vtable(&self) -> &HashMap { &self.vtable } impl_create!(name: impl ToString); } impl Debug for Ty { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "", 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::() { // 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. 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() ); // Additionally, we want to duplicate the type argument on the stack. // // When you call a new constructor, e.g. `MyType(arg1, arg2, arg3)`, the stack will look like this: // // -- stack top // arg3 // arg2 // arg1 // <---- NOTE - this is what we are actually calling, and is being treated as a function // ... // -- stack bottom // // With a custom type, we want to be getting the __init__ function off of the type. Since // we don't have access to the function in the call stack (in this case, it's our type), // we duplicate the type to be the first argument. vm.stack_mut().insert(index, this); let function = self .vtable .get("__call__") .expect("Why does a type not have a __call__ member?"); function.borrow().call(vm, argc + 1); } fn arity(&self) -> Option { // 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), to_list => BuiltinFunction::create("to_list", 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), // Methods len => BuiltinFunction::create("len", BaseObj::not_implemented_un, 1), }, Obj { // Constructor __call__ => BuiltinFunction::create("__call__", Obj::do_call, 1), __init__ => BuiltinFunction::create("__init__", Obj::init, 1), // Methods }, List { // Conversion methods to_repr => BuiltinFunction::create("to_repr", List::to_repr, 1), to_list => BuiltinFunction::create("to_list", List::to_list, 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 len => BuiltinFunction::create("len", List::len, 1), push => BuiltinFunction::create("push", List::push, 2), pop => BuiltinFunction::create("pop", List::pop, 1), extend => BuiltinFunction::create("extend", List::extend, 2), }, 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), to_list => BuiltinFunction::create("to_list", Str::to_list, 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), __index__ => BuiltinFunction::create("__index__", Str::index, 2), // Methods len => BuiltinFunction::create("len", Str::len, 1), // TODO Str methods - .lower, .upper, .slice, etc }, 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), // Methods }, 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), // Methods }, 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 // Methods }, Nil { // Conversion methods // Constructor __call__ => BuiltinFunction::create("__call__", Nil::do_call, 1), __init__ => BuiltinFunction::create("__init__", Nil::init, 1), // Operators // Methods }, BuiltinFunction { // Conversion methods // Constructor // Operators // Methods }, UserFunction { // Conversion methods // Constructor // Operators // Methods }, Method { // Conversion methods // Constructor // Operators // Methods }, Module { // Conversion methods // Constructor // Operators // Methods }, } }