ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields, ObjString* name) { // Create the metaclass. Value metaclassName = wrenStringFormat(vm, "@ metaclass", OBJ_VAL(name)); wrenPushRoot(vm, AS_OBJ(metaclassName)); ObjClass* metaclass = wrenNewSingleClass(vm, 0, AS_STRING(metaclassName)); metaclass->obj.classObj = vm->classClass; wrenPopRoot(vm); // Make sure the metaclass isn't collected when we allocate the class. wrenPushRoot(vm, (Obj*)metaclass); // Metaclasses always inherit Class and do not parallel the non-metaclass // hierarchy. wrenBindSuperclass(vm, metaclass, vm->classClass); ObjClass* classObj = wrenNewSingleClass(vm, numFields, name); // Make sure the class isn't collected while the inherited methods are being // bound. wrenPushRoot(vm, (Obj*)classObj); classObj->obj.classObj = metaclass; wrenBindSuperclass(vm, classObj, superclass); wrenPopRoot(vm); wrenPopRoot(vm); return classObj; }
// Creates either the Object or Class class in the core module with [name]. static ObjClass* defineClass(WrenVM* vm, ObjModule* module, const char* name) { ObjString* nameString = AS_STRING(wrenStringFormat(vm, "$", name)); wrenPushRoot(vm, (Obj*)nameString); ObjClass* classObj = wrenNewSingleClass(vm, 0, nameString); wrenDefineVariable(vm, module, name, nameString->length, OBJ_VAL(classObj)); wrenPopRoot(vm); return classObj; }
ObjClass* wrenNewSingleClass(WrenVM* vm, int numFields, ObjString* name) { ObjClass* classObj = ALLOCATE(vm, ObjClass); initObj(vm, &classObj->obj, OBJ_CLASS, NULL); classObj->superclass = NULL; classObj->numFields = numFields; classObj->name = name; wrenPushRoot(vm, (Obj*)classObj); wrenMethodBufferInit(&classObj->methods); wrenPopRoot(vm); return classObj; }
void wrenInitializeCore(WrenVM* vm) { ObjModule* coreModule = wrenNewModule(vm, NULL); wrenPushRoot(vm, (Obj*)coreModule); // The core module's key is null in the module map. wrenMapSet(vm, vm->modules, NULL_VAL, OBJ_VAL(coreModule)); wrenPopRoot(vm); // coreModule. // Define the root Object class. This has to be done a little specially // because it has no superclass. vm->objectClass = defineClass(vm, coreModule, "Object"); PRIMITIVE(vm->objectClass, "!", object_not); PRIMITIVE(vm->objectClass, "==(_)", object_eqeq); PRIMITIVE(vm->objectClass, "!=(_)", object_bangeq); PRIMITIVE(vm->objectClass, "is(_)", object_is); PRIMITIVE(vm->objectClass, "toString", object_toString); PRIMITIVE(vm->objectClass, "type", object_type); // Now we can define Class, which is a subclass of Object. vm->classClass = defineClass(vm, coreModule, "Class"); wrenBindSuperclass(vm, vm->classClass, vm->objectClass); PRIMITIVE(vm->classClass, "name", class_name); PRIMITIVE(vm->classClass, "supertype", class_supertype); PRIMITIVE(vm->classClass, "toString", class_toString); // Finally, we can define Object's metaclass which is a subclass of Class. ObjClass* objectMetaclass = defineClass(vm, coreModule, "Object metaclass"); // Wire up the metaclass relationships now that all three classes are built. vm->objectClass->obj.classObj = objectMetaclass; objectMetaclass->obj.classObj = vm->classClass; vm->classClass->obj.classObj = vm->classClass; // Do this after wiring up the metaclasses so objectMetaclass doesn't get // collected. wrenBindSuperclass(vm, objectMetaclass, vm->classClass); PRIMITIVE(objectMetaclass, "same(_,_)", object_same); // The core class diagram ends up looking like this, where single lines point // to a class's superclass, and double lines point to its metaclass: // // .------------------------------------. .====. // | .---------------. | # # // v | v | v # // .---------. .-------------------. .-------. # // | Object |==>| Object metaclass |==>| Class |==" // '---------' '-------------------' '-------' // ^ ^ ^ ^ ^ // | .--------------' # | # // | | # | # // .---------. .-------------------. # | # -. // | Base |==>| Base metaclass |======" | # | // '---------' '-------------------' | # | // ^ | # | // | .------------------' # | Example classes // | | # | // .---------. .-------------------. # | // | Derived |==>| Derived metaclass |==========" | // '---------' '-------------------' -' // The rest of the classes can now be defined normally. wrenInterpretInModule(vm, NULL, coreModuleSource); vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool")); PRIMITIVE(vm->boolClass, "toString", bool_toString); PRIMITIVE(vm->boolClass, "!", bool_not); vm->fiberClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fiber")); PRIMITIVE(vm->fiberClass->obj.classObj, "new(_)", fiber_new); PRIMITIVE(vm->fiberClass->obj.classObj, "abort(_)", fiber_abort); PRIMITIVE(vm->fiberClass->obj.classObj, "current", fiber_current); PRIMITIVE(vm->fiberClass->obj.classObj, "suspend()", fiber_suspend); PRIMITIVE(vm->fiberClass->obj.classObj, "yield()", fiber_yield); PRIMITIVE(vm->fiberClass->obj.classObj, "yield(_)", fiber_yield1); PRIMITIVE(vm->fiberClass, "call()", fiber_call); PRIMITIVE(vm->fiberClass, "call(_)", fiber_call1); PRIMITIVE(vm->fiberClass, "error", fiber_error); PRIMITIVE(vm->fiberClass, "isDone", fiber_isDone); PRIMITIVE(vm->fiberClass, "transfer()", fiber_transfer); PRIMITIVE(vm->fiberClass, "transfer(_)", fiber_transfer1); PRIMITIVE(vm->fiberClass, "transferError(_)", fiber_transferError); PRIMITIVE(vm->fiberClass, "try()", fiber_try); vm->fnClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fn")); PRIMITIVE(vm->fnClass->obj.classObj, "new(_)", fn_new); PRIMITIVE(vm->fnClass, "arity", fn_arity); fnCall(vm, "call()"); fnCall(vm, "call(_)"); fnCall(vm, "call(_,_)"); fnCall(vm, "call(_,_,_)"); fnCall(vm, "call(_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)"); fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)"); PRIMITIVE(vm->fnClass, "toString", fn_toString); vm->nullClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Null")); PRIMITIVE(vm->nullClass, "!", null_not); PRIMITIVE(vm->nullClass, "toString", null_toString); vm->numClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Num")); PRIMITIVE(vm->numClass->obj.classObj, "fromString(_)", num_fromString); PRIMITIVE(vm->numClass->obj.classObj, "pi", num_pi); PRIMITIVE(vm->numClass, "-(_)", num_minus); PRIMITIVE(vm->numClass, "+(_)", num_plus); PRIMITIVE(vm->numClass, "*(_)", num_multiply); PRIMITIVE(vm->numClass, "/(_)", num_divide); PRIMITIVE(vm->numClass, "<(_)", num_lt); PRIMITIVE(vm->numClass, ">(_)", num_gt); PRIMITIVE(vm->numClass, "<=(_)", num_lte); PRIMITIVE(vm->numClass, ">=(_)", num_gte); PRIMITIVE(vm->numClass, "&(_)", num_bitwiseAnd); PRIMITIVE(vm->numClass, "|(_)", num_bitwiseOr); PRIMITIVE(vm->numClass, "^(_)", num_bitwiseXor); PRIMITIVE(vm->numClass, "<<(_)", num_bitwiseLeftShift); PRIMITIVE(vm->numClass, ">>(_)", num_bitwiseRightShift); PRIMITIVE(vm->numClass, "abs", num_abs); PRIMITIVE(vm->numClass, "acos", num_acos); PRIMITIVE(vm->numClass, "asin", num_asin); PRIMITIVE(vm->numClass, "atan", num_atan); PRIMITIVE(vm->numClass, "ceil", num_ceil); PRIMITIVE(vm->numClass, "cos", num_cos); PRIMITIVE(vm->numClass, "floor", num_floor); PRIMITIVE(vm->numClass, "-", num_negate); PRIMITIVE(vm->numClass, "sin", num_sin); PRIMITIVE(vm->numClass, "sqrt", num_sqrt); PRIMITIVE(vm->numClass, "tan", num_tan); PRIMITIVE(vm->numClass, "%(_)", num_mod); PRIMITIVE(vm->numClass, "~", num_bitwiseNot); PRIMITIVE(vm->numClass, "..(_)", num_dotDot); PRIMITIVE(vm->numClass, "...(_)", num_dotDotDot); PRIMITIVE(vm->numClass, "atan(_)", num_atan2); PRIMITIVE(vm->numClass, "fraction", num_fraction); PRIMITIVE(vm->numClass, "isInfinity", num_isInfinity); PRIMITIVE(vm->numClass, "isInteger", num_isInteger); PRIMITIVE(vm->numClass, "isNan", num_isNan); PRIMITIVE(vm->numClass, "sign", num_sign); PRIMITIVE(vm->numClass, "toString", num_toString); PRIMITIVE(vm->numClass, "truncate", num_truncate); // These are defined just so that 0 and -0 are equal, which is specified by // IEEE 754 even though they have different bit representations. PRIMITIVE(vm->numClass, "==(_)", num_eqeq); PRIMITIVE(vm->numClass, "!=(_)", num_bangeq); vm->stringClass = AS_CLASS(wrenFindVariable(vm, coreModule, "String")); PRIMITIVE(vm->stringClass->obj.classObj, "fromCodePoint(_)", string_fromCodePoint); PRIMITIVE(vm->stringClass, "+(_)", string_plus); PRIMITIVE(vm->stringClass, "[_]", string_subscript); PRIMITIVE(vm->stringClass, "byteAt_(_)", string_byteAt); PRIMITIVE(vm->stringClass, "byteCount_", string_byteCount); PRIMITIVE(vm->stringClass, "codePointAt_(_)", string_codePointAt); PRIMITIVE(vm->stringClass, "contains(_)", string_contains); PRIMITIVE(vm->stringClass, "endsWith(_)", string_endsWith); PRIMITIVE(vm->stringClass, "indexOf(_)", string_indexOf); PRIMITIVE(vm->stringClass, "iterate(_)", string_iterate); PRIMITIVE(vm->stringClass, "iterateByte_(_)", string_iterateByte); PRIMITIVE(vm->stringClass, "iteratorValue(_)", string_iteratorValue); PRIMITIVE(vm->stringClass, "startsWith(_)", string_startsWith); PRIMITIVE(vm->stringClass, "toString", string_toString); vm->listClass = AS_CLASS(wrenFindVariable(vm, coreModule, "List")); PRIMITIVE(vm->listClass->obj.classObj, "new()", list_new); PRIMITIVE(vm->listClass, "[_]", list_subscript); PRIMITIVE(vm->listClass, "[_]=(_)", list_subscriptSetter); PRIMITIVE(vm->listClass, "add(_)", list_add); PRIMITIVE(vm->listClass, "addCore_(_)", list_addCore); PRIMITIVE(vm->listClass, "clear()", list_clear); PRIMITIVE(vm->listClass, "count", list_count); PRIMITIVE(vm->listClass, "insert(_,_)", list_insert); PRIMITIVE(vm->listClass, "iterate(_)", list_iterate); PRIMITIVE(vm->listClass, "iteratorValue(_)", list_iteratorValue); PRIMITIVE(vm->listClass, "removeAt(_)", list_removeAt); vm->mapClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Map")); PRIMITIVE(vm->mapClass->obj.classObj, "new()", map_new); PRIMITIVE(vm->mapClass, "[_]", map_subscript); PRIMITIVE(vm->mapClass, "[_]=(_)", map_subscriptSetter); PRIMITIVE(vm->mapClass, "addCore_(_,_)", map_addCore); PRIMITIVE(vm->mapClass, "clear()", map_clear); PRIMITIVE(vm->mapClass, "containsKey(_)", map_containsKey); PRIMITIVE(vm->mapClass, "count", map_count); PRIMITIVE(vm->mapClass, "remove(_)", map_remove); PRIMITIVE(vm->mapClass, "iterate_(_)", map_iterate); PRIMITIVE(vm->mapClass, "keyIteratorValue_(_)", map_keyIteratorValue); PRIMITIVE(vm->mapClass, "valueIteratorValue_(_)", map_valueIteratorValue); vm->rangeClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Range")); PRIMITIVE(vm->rangeClass, "from", range_from); PRIMITIVE(vm->rangeClass, "to", range_to); PRIMITIVE(vm->rangeClass, "min", range_min); PRIMITIVE(vm->rangeClass, "max", range_max); PRIMITIVE(vm->rangeClass, "isInclusive", range_isInclusive); PRIMITIVE(vm->rangeClass, "iterate(_)", range_iterate); PRIMITIVE(vm->rangeClass, "iteratorValue(_)", range_iteratorValue); PRIMITIVE(vm->rangeClass, "toString", range_toString); ObjClass* systemClass = AS_CLASS(wrenFindVariable(vm, coreModule, "System")); PRIMITIVE(systemClass->obj.classObj, "clock", system_clock); PRIMITIVE(systemClass->obj.classObj, "gc()", system_gc); // TODO: Do we want to give these magic names that can't be called from // regular code? PRIMITIVE(systemClass->obj.classObj, "getModuleVariable(_,_)", system_getModuleVariable); PRIMITIVE(systemClass->obj.classObj, "importModule(_)", system_importModule); PRIMITIVE(systemClass->obj.classObj, "writeString_(_)", system_writeString); // While bootstrapping the core types and running the core module, a number // of string objects have been created, many of which were instantiated // before stringClass was stored in the VM. Some of them *must* be created // first -- the ObjClass for string itself has a reference to the ObjString // for its name. // // These all currently have a NULL classObj pointer, so go back and assign // them now that the string class is known. for (Obj* obj = vm->first; obj != NULL; obj = obj->next) { if (obj->type == OBJ_STRING) obj->classObj = vm->stringClass; } }