Skip to content
This repository was archived by the owner on May 24, 2022. It is now read-only.

Commit 1e9e01f

Browse files
committed
Finish CLOSURE
1 parent 46c63e9 commit 1e9e01f

File tree

11 files changed

+306
-34
lines changed

11 files changed

+306
-34
lines changed

examples/fib.meon

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ func fib(n)
33
return fib(n - 2) + fib(n - 1);
44
endfunc
55

6-
let start = time();
7-
output "ELAPSED TIME => " . fib(35);
8-
output time() - start;
6+
let start = clock();
7+
output "RESULT => " . fib(35);
8+
output "ELAPSED => " . (clock() - start) . "s";

includes/chunk.h

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ typedef enum
1818
//OP_DEFINE_LOCAL,
1919
OP_SET_LOCAL,
2020
OP_SET_GLOBAL,
21+
OP_GET_UPVALUE,
22+
OP_SET_UPVALUE,
23+
OP_CLOSE_UPVALUE,
2124
OP_EQUAL,
2225
OP_GREATER,
2326
OP_GREATER_EQUAL,
@@ -37,6 +40,7 @@ typedef enum
3740
OP_JUMP,
3841
OP_LOOP,
3942
OP_CALL,
43+
OP_CLOSURE,
4044
OP_RETURN
4145
} OpCode;
4246

includes/object.h

+31-7
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
#define OBJ_TYPE(value) (AS_OBJ(value)->t)
99

1010
#define IS_STRING(value) check_object_t(value, OBJECT_STRING)
11+
#define IS_CLOSURE(value) check_object_t(value, OBJECT_CLOSURE)
1112
#define IS_FUNCTION(value) check_object_t(value, OBJECT_FUNCTION)
12-
#define IS_NATIVE(value) check_object_t(value, OBJECT_NATIVE)
13+
#define IS_NATIVE(value) check_object_t(value, OBJECT_NATIVE)
1314

15+
#define AS_CLOSURE(value) ((ObjectClosure *)AS_OBJ(value))
1416
#define AS_FUNCTION(value) ((ObjectFunction *)AS_OBJ(value))
15-
#define AS_NATIVE(value) (((ObjectNative*)AS_OBJ(value))->function)
17+
#define AS_NATIVE(value) (((ObjectNative *)AS_OBJ(value))->function)
1618
#define AS_STRING(value) ((ObjectString *)AS_OBJ(value))
1719
#define AS_CSTRING(value) (((ObjectString *)AS_OBJ(value))->chars)
1820

@@ -21,6 +23,8 @@ typedef enum
2123
OBJECT_STRING,
2224
OBJECT_FUNCTION,
2325
OBJECT_NATIVE,
26+
OBJECT_CLOSURE,
27+
OBJECT_UPVALUE,
2428
} object_t;
2529

2630
struct Object
@@ -33,15 +37,17 @@ typedef struct
3337
{
3438
Object object;
3539
int argsCount;
40+
int upvalueCount;
3641
Chunk chunk;
3742
ObjectString *name;
3843
} ObjectFunction;
3944

40-
typedef Value (*NativeFn)(int argCount, Value* args);
45+
typedef Value (*NativeFn)(int argCount, Value *args);
4146

42-
typedef struct {
43-
Object object;
44-
NativeFn function;
47+
typedef struct
48+
{
49+
Object object;
50+
NativeFn function;
4551
} ObjectNative;
4652

4753
struct ObjectString
@@ -52,8 +58,26 @@ struct ObjectString
5258
uint32_t hash;
5359
};
5460

61+
typedef struct ObjectUpvalue
62+
{
63+
Object obj;
64+
Value *location;
65+
Value closed;
66+
struct ObjectUpvalue *next;
67+
} ObjectUpvalue;
68+
69+
typedef struct
70+
{
71+
Object obj;
72+
ObjectFunction *function;
73+
ObjectUpvalue **upvalues;
74+
int upvalueCount;
75+
} ObjectClosure;
76+
5577
ObjectFunction *newFunction();
56-
ObjectNative* newNative(NativeFn function);
78+
ObjectNative *newNative(NativeFn function);
79+
ObjectClosure *newClosure(ObjectFunction *function);
80+
ObjectUpvalue *newUpvalue(Value *slot);
5781
ObjectString *takeString(char *chars, int length);
5882
ObjectString *cpString(const char *chars, int length);
5983

includes/vm.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
typedef struct
1212
{
13-
ObjectFunction *function;
13+
ObjectClosure* closure;
1414
uint8_t *ip;
1515
Value *slots;
1616
} CallFrame;
@@ -23,6 +23,7 @@ typedef struct
2323
Value *stackTop;
2424
Table globals;
2525
Table strings;
26+
ObjectUpvalue* openUpvalues;
2627
Object *objects;
2728
} VM;
2829

src/compiler.c

+75-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,15 @@ typedef struct
5151
{
5252
Token name;
5353
int depth;
54+
bool isCaptured;
5455
} Local;
5556

57+
typedef struct
58+
{
59+
uint8_t index;
60+
bool isLocal;
61+
} Upvalue;
62+
5663
typedef enum
5764
{
5865
TYPE_FUNCTION,
@@ -66,6 +73,7 @@ typedef struct Compiler
6673
function_t t;
6774
Local locals[UINT8_COUNT];
6875
int localCount;
76+
Upvalue upvalues[UINT8_COUNT];
6977
int scopeDepth;
7078
} Compiler;
7179

@@ -236,6 +244,7 @@ static void initCompiler(Compiler *compiler, function_t t)
236244
local->depth = 0;
237245
local->name.start = "";
238246
local->name.length = 0;
247+
local->isCaptured = false;
239248
}
240249

241250
static ObjectFunction *endCompiler(int debugLevel)
@@ -264,7 +273,14 @@ static void endScope()
264273
current->scopeDepth--;
265274
while (current->localCount > 0 && current->locals[current->localCount - 1].depth > current->scopeDepth)
266275
{
267-
emit_b(OP_POP);
276+
if (current->locals[current->localCount - 1].isCaptured)
277+
{
278+
emit_b(OP_CLOSE_UPVALUE);
279+
}
280+
else
281+
{
282+
emit_b(OP_POP);
283+
}
268284
current->localCount--;
269285
}
270286
}
@@ -304,6 +320,51 @@ static int resolveLocal(Compiler *compiler, Token *name)
304320
return -1;
305321
}
306322

323+
static int addUpvalue(Compiler *compiler, uint8_t index, bool isLocal)
324+
{
325+
int upvalueCount = compiler->function->upvalueCount;
326+
327+
for (int i = 0; i < upvalueCount; i++)
328+
{
329+
Upvalue *upvalue = &compiler->upvalues[i];
330+
if (upvalue->index == index && upvalue->isLocal == isLocal)
331+
{
332+
return i;
333+
}
334+
}
335+
336+
if (upvalueCount == UINT8_COUNT)
337+
{
338+
error("Too many closure variables in function.");
339+
return 0;
340+
}
341+
342+
compiler->upvalues[upvalueCount].isLocal = isLocal;
343+
compiler->upvalues[upvalueCount].index = index;
344+
return compiler->function->upvalueCount++;
345+
}
346+
347+
static int resolveUpvalue(Compiler *compiler, Token *name)
348+
{
349+
if (compiler->enclosing == NULL)
350+
return -1;
351+
352+
int local = resolveLocal(compiler->enclosing, name);
353+
if (local != -1)
354+
{
355+
compiler->enclosing->locals[local].isCaptured = true;
356+
return addUpvalue(compiler, (uint8_t)local, true);
357+
}
358+
359+
int upvalue = resolveUpvalue(compiler->enclosing, name);
360+
if (upvalue != -1)
361+
{
362+
return addUpvalue(compiler, (uint8_t)upvalue, false);
363+
}
364+
365+
return -1;
366+
}
367+
307368
static void addLocal(Token name)
308369
{
309370
if (current->localCount == UINT8_COUNT)
@@ -315,6 +376,7 @@ static void addLocal(Token name)
315376
Local *local = &current->locals[current->localCount++];
316377
local->name = name;
317378
local->depth = -1;
379+
local->isCaptured = false;
318380
}
319381

320382
static void declareVariable()
@@ -523,7 +585,13 @@ static void function(function_t t)
523585

524586
// Create the function object.
525587
ObjectFunction *function = endCompiler(0);
526-
emit_bs(OP_CONSTANT, makeConstant(OBJ_VAL(function)));
588+
emit_bs(OP_CLOSURE, makeConstant(OBJ_VAL(function)));
589+
590+
for (int i = 0; i < function->upvalueCount; i++)
591+
{
592+
emit_b(compiler.upvalues[i].isLocal ? 1 : 0);
593+
emit_b(compiler.upvalues[i].index);
594+
}
527595
}
528596

529597
static void funcDeclaration()
@@ -949,6 +1017,11 @@ static void namedVariable(Token name, bool canAssign)
9491017
getOp = OP_GET_LOCAL;
9501018
setOp = OP_SET_LOCAL;
9511019
}
1020+
else if ((arg = resolveUpvalue(current, &name)) != -1)
1021+
{
1022+
getOp = OP_GET_UPVALUE;
1023+
setOp = OP_SET_UPVALUE;
1024+
}
9521025
else
9531026
{
9541027
arg = identifierConstant(&name);

src/debug.c

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdio.h>
22

33
#include "debug.h"
4+
#include "object.h"
45
#include "value.h"
56

67
void disassembleChunk(Chunk *chunk, const char *name)
@@ -84,6 +85,12 @@ int disassembleInstruction(Chunk *chunk, int offset)
8485
return constantInstruction("dvt", chunk, offset);
8586
case OP_SET_GLOBAL:
8687
return constantInstruction("gset", chunk, offset);
88+
case OP_GET_UPVALUE:
89+
return bInstruction("uvget", chunk, offset);
90+
case OP_CLOSE_UPVALUE:
91+
return simpleInstruction("uvclose", offset);
92+
case OP_SET_UPVALUE:
93+
return bInstruction("uvset", chunk, offset);
8794
case OP_EQUAL:
8895
return simpleInstruction("eq", offset);
8996
case OP_GREATER:
@@ -121,7 +128,26 @@ int disassembleInstruction(Chunk *chunk, int offset)
121128
case OP_LOOP:
122129
return jumpInstruction("loop", -1, chunk, offset);
123130
case OP_CALL:
124-
return bInstruction("call", chunk, offset);
131+
return bInstruction("call", chunk, offset);
132+
case OP_CLOSURE:
133+
{
134+
offset++;
135+
uint8_t constant = chunk->code[offset++];
136+
printf("%-16s %4d ", "OP_CLOSURE", constant);
137+
printValue(chunk->constants.values[constant]);
138+
printf("\n");
139+
140+
ObjectFunction *function = AS_FUNCTION(chunk->constants.values[constant]);
141+
for (int j = 0; j < function->upvalueCount; j++)
142+
{
143+
int isLocal = chunk->code[offset++];
144+
int index = chunk->code[offset++];
145+
printf("%04d | %s %d\n",
146+
offset - 2, isLocal ? "local" : "upvalue", index);
147+
}
148+
149+
return offset;
150+
}
125151
case OP_RETURN:
126152
return simpleInstruction("ret", offset);
127153
default:

src/mem.c

+10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ static void freeObject(Object *object)
3636
case OBJECT_NATIVE:
3737
FREE(ObjectNative, object);
3838
break;
39+
case OBJECT_CLOSURE:
40+
{
41+
ObjectClosure *closure = (ObjectClosure *)object;
42+
FREE_ARRAY(ObjectUpvalue *, closure->upvalues, closure->upvalueCount);
43+
FREE(ObjectClosure, object);
44+
break;
45+
}
46+
case OBJECT_UPVALUE:
47+
FREE(ObjectUpvalue, object);
48+
break;
3949
}
4050
}
4151

src/native.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ static void defineNative(VM *vm, const char *name, NativeFn function)
2424
void loadNativeFunction(VM *vm)
2525
{
2626
defineNative(vm, "time", getUnixEpoch);
27-
defineNative(vm, "clock", getUnixEpoch);
27+
defineNative(vm, "clock", clockNative);
2828
}

0 commit comments

Comments
 (0)