mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 14:18:42 +01:00
Global variables.
This commit is contained in:
100
src/compiler.c
100
src/compiler.c
@ -134,6 +134,17 @@ static void makeToken(Parser* parser, TokenType type);
|
||||
|
||||
// Utility:
|
||||
static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent);
|
||||
|
||||
// Parses a name token and defines a variable in the current scope with that
|
||||
// name. Returns its symbol.
|
||||
static int defineName(Compiler* compiler);
|
||||
|
||||
// Stores a variable with the previously defined symbol in the current scope.
|
||||
static void storeVariable(Compiler* compiler, int symbol);
|
||||
|
||||
// Adds the previous token's text to the symbol table and returns its index.
|
||||
static int internSymbol(Compiler* compiler);
|
||||
|
||||
static void emit(Compiler* compiler, Code code);
|
||||
static void error(Compiler* compiler, const char* format, ...);
|
||||
|
||||
@ -197,24 +208,13 @@ void statement(Compiler* compiler)
|
||||
{
|
||||
if (match(compiler, TOKEN_CLASS))
|
||||
{
|
||||
consume(compiler, TOKEN_NAME);
|
||||
|
||||
// TODO(bob): Copied from below. Unify.
|
||||
int local = addSymbol(&compiler->locals,
|
||||
compiler->parser->source + compiler->parser->previous.start,
|
||||
compiler->parser->previous.end - compiler->parser->previous.start);
|
||||
|
||||
if (local == -1)
|
||||
{
|
||||
error(compiler, "Local variable is already defined.");
|
||||
}
|
||||
int symbol = defineName(compiler);
|
||||
|
||||
// Create the empty class.
|
||||
emit(compiler, CODE_CLASS);
|
||||
|
||||
// Store it in its name.
|
||||
emit(compiler, CODE_STORE_LOCAL);
|
||||
emit(compiler, local);
|
||||
storeVariable(compiler, symbol);
|
||||
|
||||
// Compile the method definitions.
|
||||
consume(compiler, TOKEN_LEFT_BRACE);
|
||||
@ -244,15 +244,7 @@ void statement(Compiler* compiler)
|
||||
|
||||
if (match(compiler, TOKEN_VAR))
|
||||
{
|
||||
consume(compiler, TOKEN_NAME);
|
||||
int local = addSymbol(&compiler->locals,
|
||||
compiler->parser->source + compiler->parser->previous.start,
|
||||
compiler->parser->previous.end - compiler->parser->previous.start);
|
||||
|
||||
if (local == -1)
|
||||
{
|
||||
error(compiler, "Local variable is already defined.");
|
||||
}
|
||||
int symbol = defineName(compiler);
|
||||
|
||||
// TODO(bob): Allow uninitialized vars?
|
||||
consume(compiler, TOKEN_EQ);
|
||||
@ -260,8 +252,7 @@ void statement(Compiler* compiler)
|
||||
// Compile the initializer.
|
||||
expression(compiler);
|
||||
|
||||
emit(compiler, CODE_STORE_LOCAL);
|
||||
emit(compiler, local);
|
||||
storeVariable(compiler, symbol);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -314,18 +305,32 @@ void primary(Compiler* compiler)
|
||||
// Variable name.
|
||||
if (match(compiler, TOKEN_NAME))
|
||||
{
|
||||
// See if it's a local in this scope.
|
||||
int local = findSymbol(&compiler->locals,
|
||||
compiler->parser->source + compiler->parser->previous.start,
|
||||
compiler->parser->previous.end - compiler->parser->previous.start);
|
||||
if (local == -1)
|
||||
if (local != -1)
|
||||
{
|
||||
// TODO(bob): Look for globals or names in outer scopes.
|
||||
error(compiler, "Unknown variable.");
|
||||
emit(compiler, CODE_LOAD_LOCAL);
|
||||
emit(compiler, local);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(compiler, CODE_LOAD_LOCAL);
|
||||
emit(compiler, local);
|
||||
return;
|
||||
// TODO(bob): Look up names in outer local scopes.
|
||||
|
||||
// See if it's a global variable.
|
||||
int global = findSymbol(&compiler->parser->vm->globalSymbols,
|
||||
compiler->parser->source + compiler->parser->previous.start,
|
||||
compiler->parser->previous.end - compiler->parser->previous.start);
|
||||
if (global != -1)
|
||||
{
|
||||
emit(compiler, CODE_LOAD_GLOBAL);
|
||||
emit(compiler, global);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bob): Look for globals or names in outer scopes.
|
||||
error(compiler, "Unknown variable.");
|
||||
}
|
||||
|
||||
// Number.
|
||||
@ -667,7 +672,40 @@ void emit(Compiler* compiler, Code code)
|
||||
compiler->block->bytecode[compiler->numCodes++] = code;
|
||||
}
|
||||
|
||||
// Adds the previous token's text to the symbol table and returns its index.
|
||||
int defineName(Compiler* compiler)
|
||||
{
|
||||
consume(compiler, TOKEN_NAME);
|
||||
|
||||
SymbolTable* symbols;
|
||||
if (compiler->parent)
|
||||
{
|
||||
// Nested block, so this is a local variable.
|
||||
symbols = &compiler->locals;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Top level global variable.
|
||||
symbols = &compiler->parser->vm->globalSymbols;
|
||||
}
|
||||
|
||||
int symbol = addSymbol(symbols,
|
||||
compiler->parser->source + compiler->parser->previous.start,
|
||||
compiler->parser->previous.end - compiler->parser->previous.start);
|
||||
|
||||
if (symbol == -1)
|
||||
{
|
||||
error(compiler, "Variable is already defined.");
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
void storeVariable(Compiler* compiler, int symbol)
|
||||
{
|
||||
emit(compiler, compiler->parent ? CODE_STORE_LOCAL : CODE_STORE_GLOBAL);
|
||||
emit(compiler, symbol);
|
||||
}
|
||||
|
||||
int internSymbol(Compiler* compiler)
|
||||
{
|
||||
return ensureSymbol(&compiler->parser->vm->symbols,
|
||||
|
||||
20
src/vm.c
20
src/vm.c
@ -44,6 +44,10 @@ VM* newVM()
|
||||
VM* vm = malloc(sizeof(VM));
|
||||
initSymbolTable(&vm->symbols);
|
||||
|
||||
initSymbolTable(&vm->globalSymbols);
|
||||
vm->numGlobals = 0;
|
||||
|
||||
// Define the built-in classes and their methods.
|
||||
vm->blockClass = makeClass();
|
||||
|
||||
// The call method is special: neither a primitive nor a user-defined one.
|
||||
@ -251,6 +255,22 @@ Value interpret(VM* vm, ObjBlock* block)
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_LOAD_GLOBAL:
|
||||
{
|
||||
int global = frame->block->bytecode[frame->ip++];
|
||||
push(&fiber, vm->globals[global]);
|
||||
printf("load global %d to %d\n", global, fiber.stackSize - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_STORE_GLOBAL:
|
||||
{
|
||||
int global = frame->block->bytecode[frame->ip++];
|
||||
printf("store global %d from %d\n", global, fiber.stackSize - 1);
|
||||
vm->globals[global] = fiber.stack[fiber.stackSize - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_DUP:
|
||||
push(&fiber, fiber.stack[fiber.stackSize - 1]);
|
||||
printf("dup %d\n", fiber.stackSize - 1);
|
||||
|
||||
11
src/vm.h
11
src/vm.h
@ -101,6 +101,12 @@ typedef enum
|
||||
CODE_STORE_LOCAL,
|
||||
// Stores the top of stack in local slot [arg]. Does not pop it.
|
||||
|
||||
CODE_LOAD_GLOBAL,
|
||||
// Pushes the value in global slot [arg].
|
||||
|
||||
CODE_STORE_GLOBAL,
|
||||
// Stores the top of stack in global slot [arg]. Does not pop it.
|
||||
|
||||
CODE_CALL,
|
||||
// Invoke the method with symbol [arg].
|
||||
|
||||
@ -123,6 +129,11 @@ typedef struct
|
||||
ObjClass* blockClass;
|
||||
ObjClass* classClass;
|
||||
ObjClass* numClass;
|
||||
|
||||
SymbolTable globalSymbols;
|
||||
// TODO(bob): Using a fixed array is gross here.
|
||||
Value globals[MAX_SYMBOLS];
|
||||
int numGlobals;
|
||||
} VM;
|
||||
|
||||
VM* newVM();
|
||||
|
||||
Reference in New Issue
Block a user