1
0
forked from Mirror/wren

Make a few changes to methodNotFound():

- Move closer to other runtime error code.
- Make it static since it's private to wren_vm.h.
- Allocate a managed ObjString* for the message so the GC can handle it.
  That's how it ends up anyway, so this cuts out the middle man.
- Use a width specifier in sprintf() to print the canonical method name.
This commit is contained in:
Bob Nystrom
2015-01-08 22:29:37 -08:00
parent a9f1d52ef7
commit efabf20fee

View File

@ -24,34 +24,6 @@ static void* defaultReallocate(void* memory, size_t oldSize, size_t newSize)
return realloc(memory, newSize);
}
char* methodNotFound(char* className, char* symbolName)
{
// Count the number of spaces to determine number of arguments for this
// symbol.
int pos = strlen(symbolName) - 1;
while (symbolName[pos] == ' ') pos--;
int arguments = strlen(symbolName) - pos - 1;
// Create a new string that contains only the symbol name.
char *canonicalizedSymbol = malloc(pos + 1);
strncpy(canonicalizedSymbol, symbolName, pos + 1);
int messageLength = strlen(className) + strlen(canonicalizedSymbol) +
(arguments > 9 ? 48 : 47) + (arguments == 1 ? 0 : 1);
char *message = malloc(messageLength);
snprintf(message, messageLength, "%s does not implement method '%s' with %d argument%s.",
className,
canonicalizedSymbol,
arguments,
arguments == 1 ? "" : "s");
free(canonicalizedSymbol);
return &message[0];
}
WrenVM* wrenNewVM(WrenConfiguration* configuration)
{
WrenReallocateFn reallocate = defaultReallocate;
@ -333,12 +305,12 @@ static void callForeign(WrenVM* vm, ObjFiber* fiber,
//
// Returns the fiber that should receive the error or `NULL` if no fiber
// caught it.
static ObjFiber* runtimeError(WrenVM* vm, ObjFiber* fiber, const char* error)
static ObjFiber* runtimeError(WrenVM* vm, ObjFiber* fiber, ObjString* error)
{
ASSERT(fiber->error == NULL, "Can only fail once.");
// Store the error in the fiber so it can be accessed later.
fiber->error = AS_STRING(wrenNewString(vm, error, strlen(error)));
fiber->error = error;
// If the caller ran this fiber using "try", give it the error.
if (fiber->callerIsTrying)
@ -355,6 +327,28 @@ static ObjFiber* runtimeError(WrenVM* vm, ObjFiber* fiber, const char* error)
return NULL;
}
// Creates a string containing an appropriate method not found error for a
// method with [symbol] on [classObj].
static ObjString* methodNotFound(WrenVM* vm, ObjClass* classObj, int symbol)
{
// Count the number of spaces to determine the number of parameters the
// method expects.
const char* methodName = vm->methodNames.data[symbol];
int methodLength = (int)strlen(methodName);
int numParams = 0;
while (methodName[methodLength - numParams - 1] == ' ') numParams++;
char message[MAX_VARIABLE_NAME + MAX_METHOD_NAME + 49];
sprintf(message, "%s does not implement method '%.*s' with %d argument%s.",
classObj->name->value,
methodLength - numParams, methodName,
numParams,
numParams == 1 ? "" : "s");
return AS_STRING(wrenNewString(vm, message, strlen(message)));
}
// Pushes [function] onto [fiber]'s callstack and invokes it. Expects [numArgs]
// arguments (including the receiver) to be on the top of the stack already.
// [function] can be an `ObjFn` or `ObjClosure`.
@ -603,10 +597,7 @@ static bool runInterpreter(WrenVM* vm)
// If the class's method table doesn't include the symbol, bail.
if (symbol >= classObj->methods.count)
{
char *message = methodNotFound(classObj->name->value,
vm->methodNames.data[symbol]);
RUNTIME_ERROR(message);
free(message);
RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
}
Method* method = &classObj->methods.data[symbol];
@ -626,7 +617,7 @@ static bool runInterpreter(WrenVM* vm)
break;
case PRIM_ERROR:
RUNTIME_ERROR(AS_CSTRING(args[0]));
RUNTIME_ERROR(AS_STRING(args[0]));
case PRIM_CALL:
STORE_FRAME();
@ -654,12 +645,8 @@ static bool runInterpreter(WrenVM* vm)
break;
case METHOD_NONE:
{
char *message = methodNotFound(classObj->name->value,
vm->methodNames.data[symbol]);
RUNTIME_ERROR(message);
free(message);
}
RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
break;
}
DISPATCH();
}
@ -705,10 +692,7 @@ static bool runInterpreter(WrenVM* vm)
// If the class's method table doesn't include the symbol, bail.
if (symbol >= classObj->methods.count)
{
char *message = methodNotFound(classObj->name->value,
vm->methodNames.data[symbol]);
RUNTIME_ERROR(message);
free(message);
RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
}
Method* method = &classObj->methods.data[symbol];
@ -728,7 +712,7 @@ static bool runInterpreter(WrenVM* vm)
break;
case PRIM_ERROR:
RUNTIME_ERROR(AS_CSTRING(args[0]));
RUNTIME_ERROR(AS_STRING(args[0]));
case PRIM_CALL:
STORE_FRAME();
@ -756,12 +740,8 @@ static bool runInterpreter(WrenVM* vm)
break;
case METHOD_NONE:
{
char *message = methodNotFound(classObj->name->value,
vm->methodNames.data[symbol]);
RUNTIME_ERROR(message);
free(message);
}
RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
break;
}
DISPATCH();
}
@ -884,7 +864,11 @@ static bool runInterpreter(WrenVM* vm)
CASE_CODE(IS):
{
Value expected = POP();
if (!IS_CLASS(expected)) RUNTIME_ERROR("Right operand must be a class.");
if (!IS_CLASS(expected))
{
const char* message = "Right operand must be a class.";
RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
}
ObjClass* actual = wrenGetClass(vm, POP());
bool isInstance = false;
@ -1031,7 +1015,8 @@ static bool runInterpreter(WrenVM* vm)
snprintf(message, 70 + MAX_VARIABLE_NAME,
"Class '%s' may not have more than %d fields, including inherited "
"ones.", name->value, MAX_FIELDS);
RUNTIME_ERROR(message);
RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
}
PUSH(OBJ_VAL(classObj));