Chapter 25.2
This commit is contained in:
parent
1ae50814d3
commit
e74cbddb04
7 changed files with 74 additions and 0 deletions
|
@ -15,6 +15,8 @@ typedef enum {
|
||||||
OP_GET_GLOBAL,
|
OP_GET_GLOBAL,
|
||||||
OP_DEFINE_GLOBAL,
|
OP_DEFINE_GLOBAL,
|
||||||
OP_SET_GLOBAL,
|
OP_SET_GLOBAL,
|
||||||
|
OP_GET_UPVALUE,
|
||||||
|
OP_SET_UPVALUE,
|
||||||
OP_EQUAL,
|
OP_EQUAL,
|
||||||
OP_GREATER,
|
OP_GREATER,
|
||||||
OP_LESS,
|
OP_LESS,
|
||||||
|
|
|
@ -44,6 +44,11 @@ typedef struct {
|
||||||
int depth;
|
int depth;
|
||||||
} Local;
|
} Local;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t index;
|
||||||
|
bool isLocal;
|
||||||
|
} Upvalue;
|
||||||
|
|
||||||
typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType;
|
typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType;
|
||||||
|
|
||||||
typedef struct Compiler {
|
typedef struct Compiler {
|
||||||
|
@ -53,9 +58,12 @@ typedef struct Compiler {
|
||||||
|
|
||||||
Local locals[UINT8_COUNT];
|
Local locals[UINT8_COUNT];
|
||||||
int localCount;
|
int localCount;
|
||||||
|
Upvalue upvalues[UINT8_COUNT];
|
||||||
int scopeDepth;
|
int scopeDepth;
|
||||||
} Compiler;
|
} Compiler;
|
||||||
|
|
||||||
|
static int resolveUpvalue(Compiler *, Token *);
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
Compiler *current = NULL;
|
Compiler *current = NULL;
|
||||||
Chunk *compilingChunk;
|
Chunk *compilingChunk;
|
||||||
|
@ -340,6 +348,11 @@ static void function(FunctionType type) {
|
||||||
|
|
||||||
ObjFunction *function = endCompiler();
|
ObjFunction *function = endCompiler();
|
||||||
emitBytes(OP_CLOSURE, makeConstant(OBJ_VAL(function)));
|
emitBytes(OP_CLOSURE, makeConstant(OBJ_VAL(function)));
|
||||||
|
|
||||||
|
for (int i = 0; i < function->upvalueCount; i++) {
|
||||||
|
emitByte(compiler.upvalues[i].isLocal ? 1 : 0);
|
||||||
|
emitByte(compiler.upvalues[i].index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void markInitialized() {
|
static void markInitialized() {
|
||||||
|
@ -567,6 +580,9 @@ static void namedVariable(Token name, bool canAssign) {
|
||||||
if (arg != -1) {
|
if (arg != -1) {
|
||||||
getOp = OP_GET_LOCAL;
|
getOp = OP_GET_LOCAL;
|
||||||
setOp = OP_SET_LOCAL;
|
setOp = OP_SET_LOCAL;
|
||||||
|
} else if ((arg = resolveUpvalue(current, &name)) != -1) {
|
||||||
|
getOp = OP_GET_UPVALUE;
|
||||||
|
setOp = OP_SET_UPVALUE;
|
||||||
} else {
|
} else {
|
||||||
arg = identifierConstant(&name);
|
arg = identifierConstant(&name);
|
||||||
getOp = OP_GET_GLOBAL;
|
getOp = OP_GET_GLOBAL;
|
||||||
|
@ -698,6 +714,43 @@ static int resolveLocal(Compiler *compiler, Token *name) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int addUpvalue(Compiler *compiler, uint8_t index, bool isLocal) {
|
||||||
|
int upvalueCount = compiler->function->upvalueCount;
|
||||||
|
|
||||||
|
for (int i = 0; i < upvalueCount; i++) {
|
||||||
|
Upvalue *upvalue = &compiler->upvalues[i];
|
||||||
|
if (upvalue->index == index && upvalue->isLocal == isLocal) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upvalueCount == UINT8_COUNT) {
|
||||||
|
error("Too many closure variables in function.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler->upvalues[upvalueCount].isLocal = isLocal;
|
||||||
|
compiler->upvalues[upvalueCount].index = index;
|
||||||
|
return compiler->function->upvalueCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resolveUpvalue(Compiler *compiler, Token *name) {
|
||||||
|
if (compiler->enclosing == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int local = resolveLocal(compiler->enclosing, name);
|
||||||
|
if (local != -1) {
|
||||||
|
return addUpvalue(compiler, (uint8_t)local, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int upvalue = resolveUpvalue(compiler->enclosing, name);
|
||||||
|
if (upvalue != -1) {
|
||||||
|
return addUpvalue(compiler, (uint8_t)upvalue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void addLocal(Token name) {
|
static void addLocal(Token name) {
|
||||||
if (current->localCount == UINT8_COUNT) {
|
if (current->localCount == UINT8_COUNT) {
|
||||||
error("Too many local variables in function.");
|
error("Too many local variables in function.");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "object.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
void disassembleChunk(Chunk *chunk, const char *name) {
|
void disassembleChunk(Chunk *chunk, const char *name) {
|
||||||
|
@ -68,6 +69,10 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
||||||
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
|
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
|
||||||
case OP_SET_GLOBAL:
|
case OP_SET_GLOBAL:
|
||||||
return constantInstruction("OP_SET_GLOBAL", chunk, offset);
|
return constantInstruction("OP_SET_GLOBAL", chunk, offset);
|
||||||
|
case OP_GET_UPVALUE:
|
||||||
|
return byteInstruction("OP_GET_UPVALUE", chunk, offset);
|
||||||
|
case OP_SET_UPVALUE:
|
||||||
|
return byteInstruction("OP_SET_UPVALUE", chunk, offset);
|
||||||
case OP_EQUAL:
|
case OP_EQUAL:
|
||||||
return simpleInstruction("OP_EQUAL", offset);
|
return simpleInstruction("OP_EQUAL", offset);
|
||||||
case OP_GREATER:
|
case OP_GREATER:
|
||||||
|
@ -102,6 +107,15 @@ int disassembleInstruction(Chunk *chunk, int offset) {
|
||||||
printf("%-16s %4d", "OP_CLOSURE", constant);
|
printf("%-16s %4d", "OP_CLOSURE", constant);
|
||||||
printValue(chunk->constants.values[constant]);
|
printValue(chunk->constants.values[constant]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
ObjFunction *function = AS_FUNCTION(chunk->constants.values[constant]);
|
||||||
|
for (int j = 0; j < function->upvalueCount; j++) {
|
||||||
|
int isLocal = chunk->code[offset++];
|
||||||
|
int index = chunk->code[offset++];
|
||||||
|
printf("%04d | %s %d\n", offset - 2,
|
||||||
|
isLocal ? "local" : "upvalue", index);
|
||||||
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
case OP_RETURN:
|
case OP_RETURN:
|
||||||
|
|
|
@ -28,6 +28,7 @@ ObjClosure *newClosure(ObjFunction *function) {
|
||||||
ObjFunction *newFunction() {
|
ObjFunction *newFunction() {
|
||||||
ObjFunction *function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION);
|
ObjFunction *function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION);
|
||||||
function->arity = 0;
|
function->arity = 0;
|
||||||
|
function->upvalueCount = 0;
|
||||||
function->name = NULL;
|
function->name = NULL;
|
||||||
initChunk(&function->chunk);
|
initChunk(&function->chunk);
|
||||||
return function;
|
return function;
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct Obj {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Obj obj;
|
Obj obj;
|
||||||
int arity;
|
int arity;
|
||||||
|
int upvalueCount;
|
||||||
Chunk chunk;
|
Chunk chunk;
|
||||||
ObjString *name;
|
ObjString *name;
|
||||||
} ObjFunction;
|
} ObjFunction;
|
||||||
|
|
|
@ -270,6 +270,7 @@ static InterpretResult run() {
|
||||||
push(NUMBER_VAL(-AS_NUMBER(pop())));
|
push(NUMBER_VAL(-AS_NUMBER(pop())));
|
||||||
break;
|
break;
|
||||||
case OP_PRINT: {
|
case OP_PRINT: {
|
||||||
|
printf("Printing!\n");
|
||||||
printValue(pop());
|
printValue(pop());
|
||||||
printf("\n");
|
printf("\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,6 +3,8 @@ fun fib(n) {
|
||||||
return fib(n - 1) + fib(n - 2);
|
return fib(n - 1) + fib(n - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print "Hello";
|
||||||
|
|
||||||
var before = clock();
|
var before = clock();
|
||||||
print fib(40);
|
print fib(40);
|
||||||
var after = clock();
|
var after = clock();
|
||||||
|
|
Loading…
Reference in a new issue