1
0
forked from Mirror/wren

Report undefined variable errors on the line where they are used.

This also more importantly ensures the error message for one has a
bounded length even if the variable name is pathologically long.
This commit is contained in:
Bob Nystrom
2016-03-16 08:00:28 -07:00
parent 1478d6b7e2
commit a6739819b2
4 changed files with 24 additions and 16 deletions

View File

@ -2213,7 +2213,8 @@ static void name(Compiler* compiler, bool canAssign)
// the hopes that we get a real definition later.
variable.index = wrenDeclareVariable(compiler->parser->vm,
compiler->parser->module,
token->start, token->length);
token->start, token->length,
token->line);
if (variable.index == -2)
{
@ -3438,14 +3439,18 @@ ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
emitOp(&compiler, CODE_RETURN);
// See if there are any implicitly declared module-level variables that never
// got an explicit definition.
// TODO: It would be nice if the error was on the line where it was used.
// got an explicit definition. They will have values that are numbers
// indicating the line where the variable was first used.
for (int i = 0; i < parser.module->variables.count; i++)
{
if (IS_UNDEFINED(parser.module->variables.data[i]))
if (IS_NUM(parser.module->variables.data[i]))
{
error(&compiler, "Variable '%s' is used but not defined.",
parser.module->variableNames.data[i].buffer);
// Synthesize a token for the original use site.
parser.previous.type = TOKEN_NAME;
parser.previous.start = parser.module->variableNames.data[i].buffer;
parser.previous.length = parser.module->variableNames.data[i].length;
parser.previous.line = (int)AS_NUM(parser.module->variables.data[i]);
error(&compiler, "Variable is used but not defined.");
}
}

View File

@ -1363,11 +1363,14 @@ Value wrenFindVariable(WrenVM* vm, ObjModule* module, const char* name)
}
int wrenDeclareVariable(WrenVM* vm, ObjModule* module, const char* name,
size_t length)
size_t length, int line)
{
if (module->variables.count == MAX_MODULE_VARS) return -2;
wrenValueBufferWrite(vm, &module->variables, UNDEFINED_VAL);
// Implicitly defined variables get a "value" that is the line where the
// variable is first used. We'll use that later to report an error on the
// right line.
wrenValueBufferWrite(vm, &module->variables, NUM_VAL(line));
return wrenSymbolTableAdd(vm, &module->variableNames, name, length);
}
@ -1387,9 +1390,10 @@ int wrenDefineVariable(WrenVM* vm, ObjModule* module, const char* name,
symbol = wrenSymbolTableAdd(vm, &module->variableNames, name, length);
wrenValueBufferWrite(vm, &module->variables, value);
}
else if (IS_UNDEFINED(module->variables.data[symbol]))
else if (IS_NUM(module->variables.data[symbol]))
{
// Explicitly declaring an implicitly declared one. Mark it as defined.
// An implicitly declared variable's value will always be a number. Now we
// have a real definition.
module->variables.data[symbol] = value;
}
else

View File

@ -154,13 +154,14 @@ Value wrenGetModuleVariable(WrenVM* vm, Value moduleName, Value variableName);
// module.
Value wrenFindVariable(WrenVM* vm, ObjModule* module, const char* name);
// Adds a new implicitly declared top-level variable named [name] to [module].
// Adds a new implicitly declared top-level variable named [name] to [module]
// based on a use site occurring on [line].
//
// Does not check to see if a variable with that name is already declared or
// defined. Returns the symbol for the new variable or -2 if there are too many
// variables defined.
int wrenDeclareVariable(WrenVM* vm, ObjModule* module, const char* name,
size_t length);
size_t length, int line);
// Adds a new top-level variable named [name] to [module].
//

View File

@ -1,6 +1,4 @@
var fn = Fn.new {
System.print(Foo)
System.print(Bar)
System.print(Foo) // expect error
System.print(Bar) // expect error
}
// expect error line 6