static void defineMethod(WrenVM* vm, const char* className, const char* methodName, int numParams, WrenForeignMethodFn methodFn, bool isStatic) { ASSERT(className != NULL, "Must provide class name."); int length = (int)strlen(methodName); ASSERT(methodName != NULL, "Must provide method name."); ASSERT(strlen(methodName) < MAX_METHOD_NAME, "Method name too long."); ASSERT(numParams >= 0, "numParams cannot be negative."); ASSERT(numParams <= MAX_PARAMETERS, "Too many parameters."); ASSERT(methodFn != NULL, "Must provide method function."); // Find or create the class to bind the method to. int classSymbol = wrenSymbolTableFind(&vm->globalNames, className, strlen(className)); ObjClass* classObj; if (classSymbol != -1) { // TODO: Handle name is not class. classObj = AS_CLASS(vm->globals.data[classSymbol]); } else { // The class doesn't already exist, so create it. size_t length = strlen(className); ObjString* nameString = AS_STRING(wrenNewString(vm, className, length)); WREN_PIN(vm, nameString); // TODO: Allow passing in name for superclass? classObj = wrenNewClass(vm, vm->objectClass, 0, nameString); wrenDefineGlobal(vm, className, length, OBJ_VAL(classObj)); WREN_UNPIN(vm); } // Create a name for the method, including its arity. char name[MAX_METHOD_SIGNATURE]; strncpy(name, methodName, length); for (int i = 0; i < numParams; i++) { name[length++] = ' '; } name[length] = '\0'; // Bind the method. int methodSymbol = wrenSymbolTableEnsure(vm, &vm->methodNames, name, length); Method method; method.type = METHOD_FOREIGN; method.fn.foreign = methodFn; if (isStatic) classObj = classObj->obj.classObj; wrenBindMethod(vm, classObj, methodSymbol, method); }
// Defines one of the overloads of the special "call(...)" method on Fn. // // These methods have their own unique method type to handle pushing the // function onto the callstack and checking its arity. static void fnCall(WrenVM* vm, const char* signature) { int symbol = wrenSymbolTableEnsure(vm, &vm->methodNames, signature, strlen(signature)); Method method; method.type = METHOD_FN_CALL; wrenBindMethod(vm, vm->fnClass, symbol, method); }
void wrenBindSuperclass(WrenVM* vm, ObjClass* subclass, ObjClass* superclass) { ASSERT(superclass != NULL, "Must have superclass."); subclass->superclass = superclass; // Include the superclass in the total number of fields. subclass->numFields += superclass->numFields; // Inherit methods from its superclass. for (int i = 0; i < superclass->methods.count; i++) { wrenBindMethod(vm, subclass, i, superclass->methods.data[i]); } }
static void bindMethod(WrenVM* vm, int methodType, int symbol, ObjClass* classObj, Value methodValue) { ObjFn* methodFn = IS_FN(methodValue) ? AS_FN(methodValue) : AS_CLOSURE(methodValue)->fn; // Methods are always bound against the class, and not the metaclass, even // for static methods, so that constructors (which are static) get bound like // instance methods. wrenBindMethodCode(classObj, methodFn); Method method; method.type = METHOD_BLOCK; method.fn.obj = AS_OBJ(methodValue); if (methodType == CODE_METHOD_STATIC) { classObj = classObj->obj.classObj; } wrenBindMethod(vm, classObj, symbol, method); }
void wrenBindSuperclass(WrenVM* vm, ObjClass* subclass, ObjClass* superclass) { ASSERT(superclass != NULL, "Must have superclass."); subclass->superclass = superclass; // Include the superclass in the total number of fields. if (subclass->numFields != -1) { subclass->numFields += superclass->numFields; } else { ASSERT(superclass->numFields == 0, "A foreign class cannot inherit from a class with fields."); } // Inherit methods from its superclass. for (int i = 0; i < superclass->methods.count; i++) { wrenBindMethod(vm, subclass, i, superclass->methods.data[i]); } }