Skip to content

Commit e7b0a37

Browse files
committed
feat: introduce closures and make a design change (wrap all functions with a closure even if not exists)
1 parent b1496f9 commit e7b0a37

8 files changed

Lines changed: 67 additions & 23 deletions

File tree

src/chunk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ typedef enum
3030
OP_JUMP_IF_FALSE,
3131
OP_LOOP,
3232
OP_CALL,
33+
OP_CLOSURE,
3334
OP_RETURN,
3435
} OpCode;
3536

src/compiler.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ static void function(FunctionType type)
679679
block();
680680

681681
ObjFunction* function = end_compiler();
682-
emit_bytes(OP_CONSTANT, make_constant(OBJ_VAL(function)));
682+
emit_bytes(OP_CLOSURE, make_constant(OBJ_VAL(function)));
683683
}
684684

685685
static void fun_declaration()

src/debug.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ int disassemble_instruction(Chunk* chunk, int offset)
8080
return jump_instruction("OP_JUMP_IF_FALSE", -1, chunk, offset);
8181
case OP_CALL:
8282
return byte_instruction("OP_CALL", chunk, offset);
83+
case OP_CLOSURE:
84+
{
85+
u8 constant = chunk->code[++offset];
86+
printf("%-16s %4d ", "OP_CLOSURE", constant);
87+
print_value(chunk->constants.values[constant]);
88+
printf("\n");
89+
90+
return offset;
91+
}
8392
case OP_RETURN:
8493
return simple_instruction("OP_RETURN", offset);
8594
default:

src/memory.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ static void free_object(Obj* object)
2424
{
2525
switch (object->type)
2626
{
27+
case OBJ_CLOSURE:
28+
{
29+
FREE(ObjClosure, object);
30+
break;
31+
}
2732
case OBJ_FUNCTION:
2833
{
2934
ObjFunction* function = (ObjFunction*)object;

src/object.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ static Obj* allocate_object(size_t size, ObjType type)
2323
return object;
2424
}
2525

26+
ObjClosure* new_closure(ObjFunction* function)
27+
{
28+
ObjClosure* closure = ALLOCATE_OBJ(ObjClosure, OBJ_CLOSURE);
29+
closure->function = function;
30+
return closure;
31+
}
32+
2633
ObjFunction* new_function()
2734
{
2835
ObjFunction* function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION);
@@ -108,6 +115,11 @@ void print_object(Value value)
108115

109116
switch (OBJ_TYPE(value))
110117
{
118+
case OBJ_CLOSURE:
119+
{
120+
print_function(AS_CLOSURE(value)->function);
121+
break;
122+
}
111123
case OBJ_FUNCTION:
112124
{
113125
print_function(AS_FUNCTION(value));

src/object.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
#define OBJ_TYPE(value) (AS_OBJ(value)->type)
99

10+
#define IS_CLOSURE(value) is_obj_type(value, OBJ_CLOSURE)
11+
#define AS_CLOSURE(value) ((ObjClosure*)AS_OBJ(value))
12+
1013
#define IS_FUNCTION(value) is_obj_type(value, OBJ_FUNCTION);
1114
#define AS_FUNCTION(value) (((ObjFunction*)AS_OBJ(value)))
1215

@@ -19,6 +22,7 @@
1922

2023
typedef enum
2124
{
25+
OBJ_CLOSURE,
2226
OBJ_FUNCTION,
2327
OBJ_NATIVE,
2428
OBJ_STRING,
@@ -55,6 +59,13 @@ struct ObjString
5559
u32 hash;
5660
};
5761

62+
typedef struct
63+
{
64+
Obj obj;
65+
ObjFunction* function;
66+
} ObjClosure;
67+
68+
ObjClosure* new_closure(ObjFunction* function);
5869
ObjFunction* new_function();
5970
ObjNative* new_native(NativeFn function);
6071
ObjString* take_string(char* chars, int length);

src/vm.c

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static void runtime_error(const char* format, ...)
3333
for (int i = vm.frame_count - 1; i >= 0; i--)
3434
{
3535
CallFrame* frame = &vm.frames[i];
36-
ObjFunction* function = frame->function;
36+
ObjFunction* function = frame->closure->function;
3737
size_t instruction = frame->ip - function->chunk.code - 1;
3838

3939
fprintf(stderr, "[line %d] in ", function->chunk.lines[instruction]);
@@ -89,12 +89,12 @@ static Value peek(int distance)
8989
return vm.stack_top[-1 - distance];
9090
}
9191

92-
static bool call(ObjFunction* function, int arg_count)
92+
static bool call(ObjClosure* closure, int arg_count)
9393
{
94-
if (function->arity != arg_count)
94+
if (arg_count != closure->function->arity)
9595
{
96-
runtime_error("Expected %d arguments but got %d.", function->arity,
97-
arg_count);
96+
runtime_error("Expected %d arguments but got %d.",
97+
closure->function->arity, arg_count);
9898
}
9999
if (vm.frame_count == FRAMES_MAX)
100100
{
@@ -104,8 +104,8 @@ static bool call(ObjFunction* function, int arg_count)
104104
return false;
105105
}
106106
CallFrame* frame = &vm.frames[vm.frame_count++];
107-
frame->function = function;
108-
frame->ip = function->chunk.code;
107+
frame->closure = closure;
108+
frame->ip = closure->function->chunk.code;
109109
frame->slots = vm.stack_top - arg_count - 1;
110110
return true;
111111
}
@@ -116,10 +116,8 @@ static bool call_value(Value callee, int arg_count)
116116
{
117117
switch (OBJ_TYPE(callee))
118118
{
119-
case OBJ_FUNCTION:
120-
{
121-
return call(AS_FUNCTION(callee), arg_count);
122-
}
119+
case OBJ_CLOSURE:
120+
return call(AS_CLOSURE(callee), arg_count);
123121
case OBJ_NATIVE:
124122
{
125123
NativeFn native = AS_NATIVE(callee);
@@ -164,7 +162,8 @@ static InterpretResult run()
164162

165163
#define READ_BYTE() (*frame->ip++)
166164
#define READ_SHORT() (frame->ip += 2, (u16)(frame->ip[-2] << 8) | frame->ip[-1])
167-
#define READ_CONSTANT() (frame->function->chunk.constants.values[READ_BYTE()])
165+
#define READ_CONSTANT() \
166+
(frame->closure->function->chunk.constants.values[READ_BYTE()])
168167
#define READ_STRING() AS_STRING(READ_CONSTANT())
169168
#define BINARY_OP(value_type, op) \
170169
do \
@@ -190,8 +189,9 @@ static InterpretResult run()
190189
printf(" ]");
191190
}
192191
printf("\n");
193-
disassemble_instruction(&frame->function->chunk,
194-
(int)(frame->ip - frame->function->chunk.code));
192+
disassemble_instruction(
193+
&frame->closure->function->chunk,
194+
(int)(frame->ip - frame->closure->function->chunk.code));
195195
#endif
196196
u8 instruction;
197197
switch (instruction = READ_BYTE())
@@ -342,6 +342,13 @@ static InterpretResult run()
342342
frame = &vm.frames[vm.frame_count - 1];
343343
break;
344344
}
345+
case OP_CLOSURE:
346+
{
347+
ObjFunction* function = AS_FUNCTION(READ_CONSTANT());
348+
ObjClosure* closure = new_closure(function);
349+
push(OBJ_VAL(closure));
350+
break;
351+
}
345352
case OP_RETURN:
346353
{
347354
Value result = pop();
@@ -375,11 +382,10 @@ InterpretResult interpret(char* source)
375382
return INTERPRET_COMPILE_ERROR;
376383

377384
push(OBJ_VAL(function));
378-
call_value(OBJ_VAL(function), 0);
379-
CallFrame* frame = &vm.frames[vm.frame_count++];
380-
frame->function = function;
381-
frame->ip = function->chunk.code;
382-
frame->slots = vm.stack;
385+
ObjClosure* closure = new_closure(function);
386+
pop();
387+
push(OBJ_VAL(closure));
388+
call_value(OBJ_VAL(closure), 0);
383389

384390
return run();
385391
}

src/vm.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212

1313
typedef struct
1414
{
15-
ObjFunction* function;
16-
u8* ip;
17-
Value* slots;
15+
ObjClosure* closure;
16+
u8* ip;
17+
Value* slots;
1818
} CallFrame;
1919

2020
typedef struct

0 commit comments

Comments
 (0)