1
0
forked from Mirror/wren

Rearrange the code a bit for duplicate method detections.

This commit is contained in:
Bob Nystrom
2016-03-15 07:15:55 -07:00
parent c1cea30131
commit 38699e3a81
2 changed files with 38 additions and 28 deletions

View File

@ -290,12 +290,16 @@ typedef struct
// Bookkeeping information for compiling a class definition.
typedef struct
{
// The name of the class.
ObjString* name;
// Symbol table for the fields of the class.
SymbolTable fields;
// Symbols for the methods defined by the class. Used to detect duplicate
// method definitions.
IntBuffer methods;
IntBuffer staticMethods;
IntBuffer instanceMethods;
// True if the class being compiled is a foreign class.
bool isForeign;
@ -3081,15 +3085,31 @@ 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)
// Declares a method in the enclosing class with [signature].
//
// Reports an error if a method with that signature is already declared.
// Returns the symbol for the method.
static int declareMethod(Compiler* compiler, Signature* signature,
const char* name, int length)
{
for (int i = 0; i < buffer->count; i++)
int symbol = signatureSymbol(compiler, signature);
// See if the class has already declared method with this signature.
ClassCompiler* clas = compiler->enclosingClass;
IntBuffer* methods = clas->inStatic ? &clas->staticMethods : &clas->methods;
for (int i = 0; i < methods->count; i++)
{
if (memcmp(&buffer->data[i], &data, sizeof(data)) == 0) return true;
if (methods->data[i] == symbol)
{
const char* staticPrefix = clas->inStatic ? "static " : "";
error(compiler, "Class %s already defines a %smethod '%s'.",
&compiler->enclosingClass->name->value, staticPrefix, name);
break;
}
}
return false;
wrenIntBufferWrite(compiler->parser->vm, methods, symbol);
return symbol;
}
// Compiles a method definition inside a class body.
@ -3131,6 +3151,11 @@ static bool method(Compiler* compiler, Variable classVariable)
char fullSignature[MAX_METHOD_SIGNATURE];
int length;
signatureToString(&signature, fullSignature, &length);
// Check for duplicate methods. Doesn't matter that it's already been
// defined, error will discard bytecode anyway.
// Check if the method table already contains this symbol
int methodSymbol = declareMethod(compiler, &signature, fullSignature, length);
if (isForeign)
{
@ -3151,7 +3176,6 @@ static bool method(Compiler* compiler, Variable classVariable)
// Define the method. For a constructor, this defines the instance
// initializer method.
int methodSymbol = signatureSymbol(compiler, &signature);
defineMethod(compiler, classVariable, isStatic, methodSymbol);
if (signature.type == SIG_INITIALIZER)
@ -3163,20 +3187,6 @@ static bool method(Compiler* compiler, Variable classVariable)
createConstructor(compiler, &signature, methodSymbol);
defineMethod(compiler, classVariable, true, constructorSymbol);
}
// Check for duplicate methods. Doesn't matter that it's already been
// defined, error will discard bytecode anyway.
IntBuffer* methods = isStatic ? &compiler->enclosingClass->staticMethods
: &compiler->enclosingClass->instanceMethods;
// 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.",
methodType, fullSignature, &compiler->enclosingClass->name->value);
}
wrenIntBufferWrite(compiler->parser->vm, methods, methodSymbol);
return true;
}
@ -3242,9 +3252,9 @@ static void classDefinition(Compiler* compiler, bool isForeign)
// into account.
wrenSymbolTableInit(&classCompiler.fields);
// Set up int buffers to track duplicate static and instance methods
// Set up symbol buffers to track duplicate static and instance methods.
wrenIntBufferInit(&classCompiler.methods);
wrenIntBufferInit(&classCompiler.staticMethods);
wrenIntBufferInit(&classCompiler.instanceMethods);
compiler->enclosingClass = &classCompiler;
// Compile the method definitions.
@ -3268,11 +3278,10 @@ 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
// Clear symbol tables for tracking field and method names.
wrenSymbolTableClear(compiler->parser->vm, &classCompiler.fields);
wrenIntBufferClear(compiler->parser->vm, &classCompiler.methods);
wrenIntBufferClear(compiler->parser->vm, &classCompiler.staticMethods);
wrenIntBufferClear(compiler->parser->vm, &classCompiler.instanceMethods);
compiler->enclosingClass = NULL;
popScope(compiler);
}

View File

@ -2,10 +2,11 @@ class Foo {
construct new() {}
foo() {}
foo() {} // expect error
static bar() {}
static bar() {} // expect error
// No error on instance and static method with same signature.
baz() {}
static baz() {}
}