1
0
forked from Mirror/wren

Don't use generic function for finding method duplicates and add tests

This commit is contained in:
Stephen Belanger
2016-03-12 19:14:19 -08:00
parent 4cc3afd38b
commit 6dfbea1ea4
3 changed files with 38 additions and 20 deletions

View File

@ -3082,6 +3082,17 @@ static void defineMethod(Compiler* compiler, Variable classVariable,
emitShortArg(compiler, instruction, methodSymbol);
}
// Used by `method` function below to find a method in the method list
bool hasMethod(IntBuffer* buffer, int data)
{
for (int i = 0; i < buffer->count; i++)
{
if (memcmp(&buffer->data[i], &data, sizeof(data)) == 0) return true;
}
return false;
}
// Compiles a method definition inside a class body.
//
// Returns `true` if it compiled successfully, or `false` if the method couldn't
@ -3159,13 +3170,12 @@ static bool method(Compiler* compiler, Variable classVariable)
IntBuffer* methods = isStatic ? &compiler->enclosingClass->staticMethods
: &compiler->enclosingClass->instanceMethods;
int symbol = wrenIntBufferFind(methods, methodSymbol);
if (symbol != -1)
// Check if the method table already contains this symbol
if (hasMethod(methods, methodSymbol))
{
const char* methodType = isStatic ? "static method" : "method";
error(compiler, "Already defined %s '%s' for class %s in module '%s'.",
methodType, fullSignature, &compiler->enclosingClass->name->value,
compiler->parser->module->name);
error(compiler, "Already defined %s '%s' for class %s.",
methodType, fullSignature, &compiler->enclosingClass->name->value);
}
wrenIntBufferWrite(compiler->parser->vm, methods, methodSymbol);
@ -3181,12 +3191,15 @@ static void classDefinition(Compiler* compiler, bool isForeign)
classVariable.scope = compiler->scopeDepth == -1 ? SCOPE_MODULE : SCOPE_LOCAL;
classVariable.index = declareNamedVariable(compiler);
ObjString* className = AS_STRING(wrenNewString(compiler->parser->vm,
compiler->parser->previous.start, compiler->parser->previous.length));
// Create shared class name value
Value classNameString = wrenNewString(compiler->parser->vm,
compiler->parser->previous.start, compiler->parser->previous.length);
// Create class name string to track method duplicates
ObjString* className = AS_STRING(classNameString);
// Make a string constant for the name.
emitConstant(compiler, wrenNewString(compiler->parser->vm,
compiler->parser->previous.start, compiler->parser->previous.length));
emitConstant(compiler, classNameString);
// Load the superclass (if there is one).
if (match(compiler, TOKEN_IS))
@ -3229,6 +3242,8 @@ static void classDefinition(Compiler* compiler, bool isForeign)
// bytecode will be adjusted by [wrenBindMethod] to take inherited fields
// into account.
wrenSymbolTableInit(&classCompiler.fields);
// Set up int buffers to track duplicate static and instance methods
wrenIntBufferInit(&classCompiler.staticMethods);
wrenIntBufferInit(&classCompiler.instanceMethods);
compiler->enclosingClass = &classCompiler;
@ -3254,6 +3269,8 @@ static void classDefinition(Compiler* compiler, bool isForeign)
(uint8_t)classCompiler.fields.count;
}
// Clear symbol table for tracking field names
// and int buffers for tracking duplicate methods
wrenSymbolTableClear(compiler->parser->vm, &classCompiler.fields);
wrenIntBufferClear(compiler->parser->vm, &classCompiler.staticMethods);
wrenIntBufferClear(compiler->parser->vm, &classCompiler.instanceMethods);

View File

@ -27,8 +27,7 @@ typedef struct {
void wren##name##BufferClear(WrenVM* vm, name##Buffer* buffer); \
void wren##name##BufferFill(WrenVM* vm, name##Buffer* buffer, type data, \
int count); \
void wren##name##BufferWrite(WrenVM* vm, name##Buffer* buffer, type data); \
int wren##name##BufferFind(name##Buffer* buffer, type data)
void wren##name##BufferWrite(WrenVM* vm, name##Buffer* buffer, type data)
// This should be used once for each type instantiation, somewhere in a .c file.
#define DEFINE_BUFFER(name, type) \
@ -65,15 +64,6 @@ typedef struct {
void wren##name##BufferWrite(WrenVM* vm, name##Buffer* buffer, type data) \
{ \
wren##name##BufferFill(vm, buffer, data, 1); \
} \
int wren##name##BufferFind(name##Buffer* buffer, type data) \
{ \
for (int i = 0; i < buffer->count; i++) \
{ \
if (memcmp(&buffer->data[i], &data, sizeof(data)) == 0) return i; \
} \
\
return -1; \
}
DECLARE_BUFFER(Byte, uint8_t);

View File

@ -0,0 +1,11 @@
class Foo {
construct new() {}
foo() {}
foo() {} // expect error
static bar() {}
static bar() {} // expect error
baz() {}
static baz() {}
}