Implicitly define nonlocal names.

If a capitalized name cannot be resolved, a new top-level
variable with its name is implicitly declared. If a real
definition is not found later, a compile time error is raised.

Mutual recursion at the top level works now!

Fix #101. Fix #106.
This commit is contained in:
Bob Nystrom
2015-01-14 23:08:25 -08:00
parent 74a7ac6b95
commit c50e46725f
14 changed files with 152 additions and 53 deletions
+33 -6
View File
@@ -177,7 +177,7 @@ typedef struct
int index;
} CompilerUpvalue;
// Keeps track of bookkeeping information for the current loop being compiled.
// Bookkeeping information for the current loop being compiled.
typedef struct sLoop
{
// Index of the instruction that the loop should jump back to.
@@ -296,14 +296,17 @@ static void error(Compiler* compiler, const char* format, ...)
// reported it.
if (token->type == TOKEN_ERROR) return;
fprintf(stderr, "[%s line %d] Error on ",
fprintf(stderr, "[%s line %d] Error at ",
compiler->parser->sourcePath->value, token->line);
if (token->type == TOKEN_LINE)
{
// Don't print the newline itself since that looks wonky.
fprintf(stderr, "newline: ");
}
else if (token->type == TOKEN_EOF)
{
fprintf(stderr, "end of file: ");
}
else
{
fprintf(stderr, "'%.*s': ", token->length, token->start);
@@ -1799,9 +1802,21 @@ static void name(Compiler* compiler, bool allowAssignment)
token->start, token->length);
if (global == -1)
{
// TODO: Implicitly declare it.
error(compiler, "Undefined variable.");
return;
if (isLocalName(token->start))
{
error(compiler, "Undefined variable.");
return;
}
// If it's a nonlocal name, implicitly define a global in the hopes that
// we get a real definition later.
global = wrenDeclareGlobal(compiler->parser->vm,
token->start, token->length);
if (global == -2)
{
error(compiler, "Too many global variables defined.");
}
}
variable(compiler, allowAssignment, global, CODE_LOAD_GLOBAL);
@@ -2800,6 +2815,18 @@ ObjFn* wrenCompile(WrenVM* vm, const char* sourcePath, const char* source)
emit(&compiler, CODE_NULL);
emit(&compiler, CODE_RETURN);
// See if there are any implicitly declared globals that never got an explicit
// definition.
// TODO: It would be nice if the error was on the line where it was used.
for (int i = 0; i < vm->globals.count; i++)
{
if (IS_UNDEFINED(vm->globals.data[i]))
{
error(&compiler, "Variable '%s' is used but not defined.",
vm->globalNames.data[i]);
}
}
return endCompiler(&compiler, "(script)", 8);
}