Skip to content

Commit 871a228

Browse files
committed
feat: implement classes and instances basic infra
1 parent ccc76ba commit 871a228

8 files changed

Lines changed: 100 additions & 6 deletions

File tree

src/chunk.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "chunk.h"
55
#include "memory.h"
66
#include "value.h"
7+
#include "vm.h"
78

89
void init_chunk(Chunk* chunk)
910
{
@@ -37,6 +38,8 @@ void write_chunk(Chunk* chunk, u8 byte, int line)
3738

3839
int add_constant(Chunk* chunk, Value value)
3940
{
41+
push(value);
4042
write_value_array(&chunk->constants, value);
43+
pop();
4144
return chunk->constants.count - 1;
4245
}

src/chunk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ typedef enum
3535
OP_CLOSURE,
3636
OP_CLOSE_UPVALUE,
3737
OP_RETURN,
38+
OP_CLASS,
3839
} OpCode;
3940

4041
typedef struct

src/compiler.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,19 @@ static void function(FunctionType type)
748748
}
749749
}
750750

751+
static void class_declaration()
752+
{
753+
consume(TOKEN_IDENTIFIER, "Expect class name.");
754+
u8 name_constant = identifier_constant(&parser.previous);
755+
declare_variable(true);
756+
757+
emit_bytes(OP_CLASS, name_constant);
758+
define_variable(name_constant, true);
759+
760+
consume(TOKEN_LEFT_BRACE, "Expected '{' after class name");
761+
consume(TOKEN_RIGHT_BRACE, "Expected '}' after class body");
762+
}
763+
751764
static void fun_declaration()
752765
{
753766
u8 global = parse_variable(false, "Expect function name");
@@ -930,10 +943,10 @@ static void synchronize()
930943

931944
static void declaration()
932945
{
933-
if (match(TOKEN_FUN))
934-
{
946+
if (match(TOKEN_CLASS))
947+
class_declaration();
948+
else if (match(TOKEN_FUN))
935949
fun_declaration();
936-
}
937950
else if (match(TOKEN_VAR) || match(TOKEN_VAL))
938951
var_declaration();
939952
else

src/debug.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ int disassemble_instruction(Chunk* chunk, int offset)
107107
return simple_instruction("OP_CLOSE_UPVALUE", offset);
108108
case OP_RETURN:
109109
return simple_instruction("OP_RETURN", offset);
110+
case OP_CLASS:
111+
return constant_instruction("OP_CLASS", chunk, offset);
110112
default:
111113
printf("Uknown opcode %d \n", instruction);
112114
return offset + 1;

src/memory.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ static void blacken_object(Obj* object)
9292
#endif // DEbUG_LOG_GC
9393
switch (object->type)
9494
{
95+
case OBJ_CLASS:
96+
ObjClass* klass = (ObjClass*)object;
97+
mark_object((Obj*)klass->name);
98+
break;
9599
case OBJ_CLOSURE:
96100
ObjClosure* closure = (ObjClosure*)object;
97101
mark_object((Obj*)closure->function);
@@ -105,6 +109,11 @@ static void blacken_object(Obj* object)
105109
mark_object((Obj*)function->name);
106110
mark_array(&function->chunk.constants);
107111
break;
112+
case OBJ_INSTANCE:
113+
ObjInstance* instance = (ObjInstance*)object;
114+
mark_object((Obj*)instance->klass);
115+
mark_table(&instance->fields);
116+
break;
108117
case OBJ_UPVALUE:
109118
mark_value(((ObjUpvalue*)object)->closed);
110119
break;
@@ -123,6 +132,9 @@ static void free_object(Obj* object)
123132

124133
switch (object->type)
125134
{
135+
case OBJ_CLASS:
136+
FREE(ObjClass, object);
137+
break;
126138
case OBJ_CLOSURE:
127139
{
128140
ObjClosure* closure = (ObjClosure*)object;
@@ -137,6 +149,11 @@ static void free_object(Obj* object)
137149
FREE(ObjFunction, object);
138150
break;
139151
}
152+
case OBJ_INSTANCE:
153+
ObjInstance* instance = (ObjInstance*)object;
154+
free_table(&instance->fields);
155+
FREE(ObjInstance, object);
156+
break;
140157
case OBJ_NATIVE:
141158
{
142159
FREE(ObjNative, object);

src/object.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
#include "memory.h"
99
#include "object.h"
1010
#include "table.h"
11+
#include "value.h"
1112
#include "vm.h"
1213

13-
#define ALLOCATE_OBJ(type, object_type) \
14+
#define ALLOCATE_OBJ(type, object_type) \
1415
(type*)allocate_object(sizeof(type), object_type)
1516

1617
static Obj* allocate_object(size_t size, ObjType type)
@@ -28,6 +29,13 @@ static Obj* allocate_object(size_t size, ObjType type)
2829
return object;
2930
}
3031

32+
ObjClass* new_class(ObjString* name)
33+
{
34+
ObjClass* klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS);
35+
klass->name = name;
36+
return klass;
37+
}
38+
3139
ObjClosure* new_closure(ObjFunction* function)
3240
{
3341
ObjUpvalue** upvalues = ALLOCATE(ObjUpvalue*, function->upvalue_count);
@@ -54,6 +62,14 @@ ObjFunction* new_function()
5462
return function;
5563
}
5664

65+
ObjInstance* new_instance(ObjClass* klass)
66+
{
67+
ObjInstance* instance = ALLOCATE_OBJ(ObjInstance, OBJ_INSTANCE);
68+
instance->klass = klass;
69+
init_table(&instance->fields);
70+
return instance;
71+
}
72+
5773
ObjNative* new_native(NativeFn function)
5874
{
5975
ObjNative* native = ALLOCATE_OBJ(ObjNative, OBJ_NATIVE);
@@ -68,7 +84,9 @@ static ObjString* allocate_string(char* chars, int length, u32 hash)
6884
string->chars = chars;
6985
string->hash = hash;
7086

87+
push(OBJ_VAL(string));
7188
table_set(&vm.strings, string, NIL_VAL);
89+
pop();
7290

7391
return string;
7492
}
@@ -138,6 +156,9 @@ void print_object(Value value)
138156

139157
switch (OBJ_TYPE(value))
140158
{
159+
case OBJ_CLASS:
160+
printf("%s", AS_CLASS(value)->name->chars);
161+
break;
141162
case OBJ_CLOSURE:
142163
{
143164
print_function(AS_CLOSURE(value)->function);
@@ -148,6 +169,9 @@ void print_object(Value value)
148169
print_function(AS_FUNCTION(value));
149170
break;
150171
}
172+
case OBJ_INSTANCE:
173+
printf("%s instance", AS_INSTANCE(value)->klass->name->chars);
174+
break;
151175
case OBJ_NATIVE:
152176
{
153177
printf("<native fn>");

src/object.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,23 @@
33

44
#include "chunk.h"
55
#include "common.h"
6+
#include "table.h"
67
#include "value.h"
78

89
#define OBJ_TYPE(value) (AS_OBJ(value)->type)
910

11+
#define IS_CLASS(value) is_obj_type(value, OBJ_CLASS)
12+
#define AS_CLASS(value) ((ObjClass*)AS_OBJ(value))
13+
1014
#define IS_CLOSURE(value) is_obj_type(value, OBJ_CLOSURE)
1115
#define AS_CLOSURE(value) ((ObjClosure*)AS_OBJ(value))
1216

1317
#define IS_FUNCTION(value) is_obj_type(value, OBJ_FUNCTION);
1418
#define AS_FUNCTION(value) (((ObjFunction*)AS_OBJ(value)))
1519

20+
#define IS_INSTANCE(value) is_obj_type(value, OBJ_INSTANCE)
21+
#define AS_INSTANCE(value) ((ObjInstance*)AS_OBJ(value))
22+
1623
#define IS_NATIVE(value) is_obj_type(value, OBJ_NATIVE);
1724
#define AS_NATIVE(value) (((ObjNative*)AS_OBJ(value))->function)
1825

@@ -22,8 +29,10 @@
2229

2330
typedef enum
2431
{
32+
OBJ_CLASS,
2533
OBJ_CLOSURE,
2634
OBJ_FUNCTION,
35+
OBJ_INSTANCE,
2736
OBJ_NATIVE,
2837
OBJ_STRING,
2938
OBJ_UPVALUE,
@@ -78,8 +87,23 @@ typedef struct
7887
int upvalue_count;
7988
} ObjClosure;
8089

90+
typedef struct ObjClass
91+
{
92+
Obj obj;
93+
ObjString* name;
94+
} ObjClass;
95+
96+
typedef struct ObjInstance
97+
{
98+
Obj obj;
99+
ObjClass* klass;
100+
Table fields;
101+
} ObjInstance;
102+
103+
ObjClass* new_class(ObjString* name);
81104
ObjClosure* new_closure(ObjFunction* function);
82105
ObjFunction* new_function();
106+
ObjInstance* new_instance(ObjClass* klass);
83107
ObjNative* new_native(NativeFn function);
84108
ObjString* take_string(char* chars, int length);
85109
ObjString* copy_string(const char* chars, int length);

src/vm.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ static bool call_value(Value callee, int arg_count)
124124
{
125125
switch (OBJ_TYPE(callee))
126126
{
127+
case OBJ_INSTANCE:
128+
ObjClass* klass = AS_CLASS(callee);
129+
vm.stack_top[-arg_count - 1] = OBJ_VAL(new_instance(klass));
130+
return true;
127131
case OBJ_CLOSURE:
128132
return call(AS_CLOSURE(callee), arg_count);
129133
case OBJ_NATIVE:
@@ -187,8 +191,8 @@ static bool is_falsey(Value value)
187191

188192
static void concatenate()
189193
{
190-
ObjString* b = AS_STRING(pop());
191-
ObjString* a = AS_STRING(pop());
194+
ObjString* b = AS_STRING(peek(0));
195+
ObjString* a = AS_STRING(peek(1));
192196

193197
int length = a->length + b->length;
194198
char* chars = ALLOCATE(char, length + 1);
@@ -197,6 +201,9 @@ static void concatenate()
197201
chars[length] = '\0';
198202

199203
ObjString* result = take_string(chars, length);
204+
205+
pop();
206+
pop();
200207
push(OBJ_VAL(result));
201208
}
202209

@@ -438,6 +445,9 @@ static InterpretResult run()
438445
frame = &vm.frames[vm.frame_count - 1];
439446
break;
440447
}
448+
case OP_CLASS:
449+
push(OBJ_VAL(new_class(READ_STRING())));
450+
break;
441451
}
442452
}
443453

0 commit comments

Comments
 (0)