|
| 1 | +#include "vm.h" |
1 | 2 | #include "bloat.h" |
| 3 | +#include "chunk.h" |
2 | 4 | #include "value.h" |
3 | | -#include "vm.h" |
| 5 | +#include "object.h" |
| 6 | + |
| 7 | +#include <stdio.h> |
| 8 | +#include <stdarg.h> |
| 9 | +#include <string.h> |
4 | 10 |
|
5 | 11 | static InterpretResult run(VM* vm) { |
6 | 12 | #define READ_BYTE() (*vm->ip++) |
@@ -115,18 +121,88 @@ bool values_equal(Value a, Value b) { |
115 | 121 | switch (a.type) { |
116 | 122 | case VAL_NIL: return true; |
117 | 123 | case VAL_BOOL: return AS_BOOL(a) == AS_BOOL(b); |
118 | | - case VAL_INT: return AS_INT(a) == AS_INT(b); |
119 | | - case VAL_FLOAT: return AS_FLOAT(a) == AS_FLOAT(b); |
120 | | - case VAL_STRING: return strcmp(AS_STRING(a), AS_STRING(b)) == 0; |
| 124 | + case VAL_NUMBER: return AS_NUMBER(a) == AS_NUMBER(b); |
121 | 125 | case VAL_OBJ: return AS_OBJ(a) == AS_OBJ(b); |
122 | 126 | default: return false; |
123 | 127 | } |
124 | 128 | } |
125 | 129 |
|
126 | 130 | Value peek(int offset) { |
127 | 131 | VM* vm; |
128 | | - if ((intptr_t) (vm->stack_top - offset - 1) < 0) { |
129 | | - printf("Stack underflow!"); |
| 132 | + if ((intptr_t)(vm->stack_top - offset - 1) < 0) { |
| 133 | + runtime_error("Stack underflow!"); |
| 134 | + return NIL_VAL; |
| 135 | + } |
| 136 | + return vm->stack[(int)(vm->stack_top - offset - 1)]; |
| 137 | +} |
| 138 | + |
| 139 | +void* reallocate(void* pointer, size_t oldSize, size_t newSize) { |
| 140 | + vm->bytes_allocated += newSize - oldSize; |
| 141 | + |
| 142 | + if (newSize > oldSize) { |
| 143 | + if (vm->bytes_allocated > vm->next_gc) { |
| 144 | + collect_garbage(vm); |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + if (newSize == 0) { |
| 149 | + free(pointer); |
| 150 | + return NULL; |
| 151 | + } |
| 152 | + |
| 153 | + void* result = realloc(pointer, newSize); |
| 154 | + if (result == NULL) exit(1); |
| 155 | + return result; |
| 156 | +} |
| 157 | + |
| 158 | +void collect_garbage(VM* vm) { |
| 159 | + for (Value* slot = vm->stack; slot < vm->stack_top; slot++) { |
| 160 | + mark_value(vm, *slot); |
| 161 | + } |
| 162 | + |
| 163 | + Object** object = &vm->objects; |
| 164 | + while (*object != NULL) { |
| 165 | + if (!(*object)->is_marked) { |
| 166 | + Object* unreached = *object; |
| 167 | + *object = unreached->next; |
| 168 | + free_object(unreached); |
| 169 | + } else { |
| 170 | + (*object)->is_marked = false; |
| 171 | + object = &(*object)->next; |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + vm->next_gc = vm->bytes_allocated * 2; |
| 176 | +} |
| 177 | + |
| 178 | +void mark_object(VM* vm, Object* object) { |
| 179 | + if (object == NULL) return; |
| 180 | + if (object->is_marked) return; |
| 181 | + |
| 182 | + object->is_marked = true; |
| 183 | + // If the object contains references to other objects, |
| 184 | + // they should be marked here |
| 185 | +} |
| 186 | + |
| 187 | +void mark_value(VM* vm, Value value) { |
| 188 | + if (IS_OBJ(value)) { |
| 189 | + mark_object(vm, AS_OBJ(value)); |
| 190 | + } |
| 191 | +} |
| 192 | + |
| 193 | +void runtime_error(const char* format, ...) { |
| 194 | + va_list args; |
| 195 | + va_start(args, format); |
| 196 | + vfprintf(stderr, format, args); |
| 197 | + va_end(args); |
| 198 | + fputs("\n", stderr); |
| 199 | +} |
| 200 | + |
| 201 | +void free_objects(VM* vm) { |
| 202 | + Object* object = vm->objects; |
| 203 | + while (object != NULL) { |
| 204 | + Object* next = object->next; |
| 205 | + free_object(object); |
| 206 | + object = next; |
130 | 207 | } |
131 | | - return vm->stack[(int) (vm->stack_top - offset - 1)]; |
132 | 208 | } |
0 commit comments