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; }
ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields, ObjString* name) { WREN_PIN(vm, name); // Create the metaclass. ObjString* metaclassName = wrenStringConcat(vm, name->value, " metaclass"); WREN_PIN(vm, metaclassName); ObjClass* metaclass = wrenNewSingleClass(vm, 0, metaclassName); metaclass->obj.classObj = vm->classClass; WREN_UNPIN(vm); // Make sure the metaclass isn't collected when we allocate the class. WREN_PIN(vm, 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. WREN_PIN(vm, classObj); classObj->obj.classObj = metaclass; wrenBindSuperclass(vm, classObj, superclass); WREN_UNPIN(vm); WREN_UNPIN(vm); WREN_UNPIN(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; } }
void wrenInitializeCore(WrenVM* vm) { // Define the root Object class. This has to be done a little specially // because it has no superclass and an unusual metaclass (Class). vm->objectClass = defineSingleClass(vm, "Object"); NATIVE(vm->objectClass, "== ", object_eqeq); NATIVE(vm->objectClass, "!= ", object_bangeq); NATIVE(vm->objectClass, "new", object_new); NATIVE(vm->objectClass, "toString", object_toString); NATIVE(vm->objectClass, "type", object_type); NATIVE(vm->objectClass, " instantiate", object_instantiate); // Now we can define Class, which is a subclass of Object, but Object's // metaclass. vm->classClass = defineSingleClass(vm, "Class"); // Now that Object and Class are defined, we can wire them up to each other. wrenBindSuperclass(vm, vm->classClass, vm->objectClass); vm->objectClass->metaclass = vm->classClass; vm->classClass->metaclass = vm->classClass; // Define the methods specific to Class after wiring up its superclass to // prevent the inherited ones from overwriting them. NATIVE(vm->classClass, " instantiate", class_instantiate); NATIVE(vm->classClass, "name", class_name); // 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 \\ // .---------. .--------------. // // | Object |==>| Class |==/ // '---------' '--------------' // ^ ^ // | | // .---------. .--------------. \ // | Base |==>| Base.type | | // '---------' '--------------' | // ^ ^ | Hypothetical example classes // | | | // .---------. .--------------. | // | Derived |==>| Derived.type | | // '---------' '--------------' / // The rest of the classes can not be defined normally. vm->boolClass = defineClass(vm, "Bool"); NATIVE(vm->boolClass, "toString", bool_toString); NATIVE(vm->boolClass, "!", bool_not); // TODO: Make fibers inherit Sequence and be iterable. vm->fiberClass = defineClass(vm, "Fiber"); NATIVE(vm->fiberClass->metaclass, " instantiate", fiber_instantiate); NATIVE(vm->fiberClass->metaclass, "new ", fiber_new); NATIVE(vm->fiberClass->metaclass, "yield", fiber_yield); NATIVE(vm->fiberClass->metaclass, "yield ", fiber_yield1); NATIVE(vm->fiberClass, "call", fiber_call); NATIVE(vm->fiberClass, "call ", fiber_call1); NATIVE(vm->fiberClass, "isDone", fiber_isDone); NATIVE(vm->fiberClass, "run", fiber_run); NATIVE(vm->fiberClass, "run ", fiber_run1); vm->fnClass = defineClass(vm, "Fn"); NATIVE(vm->fnClass->metaclass, " instantiate", fn_instantiate); NATIVE(vm->fnClass->metaclass, "new ", fn_new); NATIVE(vm->fnClass, "call", fn_call0); NATIVE(vm->fnClass, "call ", fn_call1); NATIVE(vm->fnClass, "call ", fn_call2); NATIVE(vm->fnClass, "call ", fn_call3); NATIVE(vm->fnClass, "call ", fn_call4); NATIVE(vm->fnClass, "call ", fn_call5); NATIVE(vm->fnClass, "call ", fn_call6); NATIVE(vm->fnClass, "call ", fn_call7); NATIVE(vm->fnClass, "call ", fn_call8); NATIVE(vm->fnClass, "call ", fn_call9); NATIVE(vm->fnClass, "call ", fn_call10); NATIVE(vm->fnClass, "call ", fn_call11); NATIVE(vm->fnClass, "call ", fn_call12); NATIVE(vm->fnClass, "call ", fn_call13); NATIVE(vm->fnClass, "call ", fn_call14); NATIVE(vm->fnClass, "call ", fn_call15); NATIVE(vm->fnClass, "call ", fn_call16); NATIVE(vm->fnClass, "toString", fn_toString); vm->nullClass = defineClass(vm, "Null"); NATIVE(vm->nullClass, "toString", null_toString); vm->numClass = defineClass(vm, "Num"); NATIVE(vm->numClass, "abs", num_abs); NATIVE(vm->numClass, "ceil", num_ceil); NATIVE(vm->numClass, "cos", num_cos); NATIVE(vm->numClass, "floor", num_floor); NATIVE(vm->numClass, "isNan", num_isNan); NATIVE(vm->numClass, "sin", num_sin); NATIVE(vm->numClass, "sqrt", num_sqrt); NATIVE(vm->numClass, "toString", num_toString) NATIVE(vm->numClass, "-", num_negate); NATIVE(vm->numClass, "- ", num_minus); NATIVE(vm->numClass, "+ ", num_plus); NATIVE(vm->numClass, "* ", num_multiply); NATIVE(vm->numClass, "/ ", num_divide); NATIVE(vm->numClass, "% ", num_mod); NATIVE(vm->numClass, "< ", num_lt); NATIVE(vm->numClass, "> ", num_gt); NATIVE(vm->numClass, "<= ", num_lte); NATIVE(vm->numClass, ">= ", num_gte); NATIVE(vm->numClass, "~", num_bitwiseNot); NATIVE(vm->numClass, "& ", num_bitwiseAnd); NATIVE(vm->numClass, "| ", num_bitwiseOr); NATIVE(vm->numClass, ".. ", num_dotDot); NATIVE(vm->numClass, "... ", num_dotDotDot); vm->stringClass = defineClass(vm, "String"); NATIVE(vm->stringClass, "contains ", string_contains); NATIVE(vm->stringClass, "count", string_count); NATIVE(vm->stringClass, "toString", string_toString) NATIVE(vm->stringClass, "+ ", string_plus); NATIVE(vm->stringClass, "== ", string_eqeq); NATIVE(vm->stringClass, "!= ", string_bangeq); NATIVE(vm->stringClass, "[ ]", string_subscript); wrenInterpret(vm, "Wren core library", libSource); vm->listClass = AS_CLASS(findGlobal(vm, "List")); NATIVE(vm->listClass->metaclass, " instantiate", list_instantiate); NATIVE(vm->listClass, "add ", list_add); NATIVE(vm->listClass, "clear", list_clear); NATIVE(vm->listClass, "count", list_count); NATIVE(vm->listClass, "insert ", list_insert); NATIVE(vm->listClass, "iterate ", list_iterate); NATIVE(vm->listClass, "iteratorValue ", list_iteratorValue); NATIVE(vm->listClass, "removeAt ", list_removeAt); NATIVE(vm->listClass, "[ ]", list_subscript); NATIVE(vm->listClass, "[ ]=", list_subscriptSetter); vm->rangeClass = AS_CLASS(findGlobal(vm, "Range")); NATIVE(vm->rangeClass, "from", range_from); NATIVE(vm->rangeClass, "to", range_to); NATIVE(vm->rangeClass, "min", range_min); NATIVE(vm->rangeClass, "max", range_max); NATIVE(vm->rangeClass, "isInclusive", range_isInclusive); NATIVE(vm->rangeClass, "iterate ", range_iterate); NATIVE(vm->rangeClass, "iteratorValue ", range_iteratorValue); NATIVE(vm->rangeClass, "toString", range_toString); // These are defined just so that 0 and -0 are equal, which is specified by // IEEE 754 even though they have different bit representations. NATIVE(vm->numClass, "== ", num_eqeq); NATIVE(vm->numClass, "!= ", num_bangeq); }