aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-21 14:28:37 +0200
committerBad Diode <bd@badd10de.dev>2021-10-21 14:28:37 +0200
commit8a8b6595ebec509f1b5ae155a38a99347820225c (patch)
treec493b51e40b7957cfdacebfeb2ba08a3ffce2e67
parentc177bfeb1dbb5ec96af3a882d708a7fca3a5e1fe (diff)
downloadbdl-8a8b6595ebec509f1b5ae155a38a99347820225c.tar.gz
bdl-8a8b6595ebec509f1b5ae155a38a99347820225c.zip
Add WIP hashtable implementation
-rw-r--r--src/bootstrap/gc.c2
-rw-r--r--src/bootstrap/gc.h2
-rw-r--r--src/bootstrap/hashtable.h158
-rwxr-xr-xsrc/bootstrap/main.c558
-rw-r--r--src/bootstrap/objects.c2
-rw-r--r--src/bootstrap/objects.h2
6 files changed, 461 insertions, 263 deletions
diff --git a/src/bootstrap/gc.c b/src/bootstrap/gc.c
index 259cccd..a188279 100644
--- a/src/bootstrap/gc.c
+++ b/src/bootstrap/gc.c
@@ -37,7 +37,7 @@ pop_active_env(void) {
37} 37}
38 38
39void 39void
40init_gc(void) { 40gc_init(void) {
41 gc = (GC){0}; 41 gc = (GC){0};
42 42
43 array_init(gc.objects, GC_OBJS_CAP); 43 array_init(gc.objects, GC_OBJS_CAP);
diff --git a/src/bootstrap/gc.h b/src/bootstrap/gc.h
index 0a0bbd0..9ad1615 100644
--- a/src/bootstrap/gc.h
+++ b/src/bootstrap/gc.h
@@ -18,7 +18,7 @@ typedef struct GC {
18 Environment **active_envs; 18 Environment **active_envs;
19} GC; 19} GC;
20 20
21void init_gc(void); 21void gc_init(void);
22 22
23// Allocation functions for objects and environments. 23// Allocation functions for objects and environments.
24Object * alloc_object(ObjectType type); 24Object * alloc_object(ObjectType type);
diff --git a/src/bootstrap/hashtable.h b/src/bootstrap/hashtable.h
new file mode 100644
index 0000000..baffec0
--- /dev/null
+++ b/src/bootstrap/hashtable.h
@@ -0,0 +1,158 @@
1#ifndef BDL_HASHTABLE_H
2#define BDL_HASHTABLE_H
3
4#include "darray.h"
5#include "objects.h"
6
7// Minimum table capacity.
8#define HT_MIN_CAP 4
9#define HT_MIN_SHIFT 2
10
11// Adjust the load factor threshold at which the table will grow on insertion.
12#define HT_LOAD_THRESHOLD 0.75
13
14typedef struct HashTablePair {
15 Object *key;
16 Object *value;
17} HashTablePair;
18
19typedef struct HashTable {
20 // All available key-value pairs as a dynamic array.
21 HashTablePair *pairs;
22
23 // This table expects the number of buckets to grow in powers of two. To
24 // speedup the default hashing, we memoize the number of bits equivalent to
25 // that power of 2:
26 //
27 // cap := 1024 = 2 ^ 10, shift_amount := 10
28 //
29 uint8_t shift_amount;
30} HashTable;
31
32// Use Fibonacci hashing to map a hash to a value in range of the table.
33static inline uint64_t
34_fibonacci_hash(uint64_t hash, size_t shift_amount) {
35 return (hash * UINT64_C(11400714819323198485)) >> (64 - shift_amount);
36}
37
38uint64_t
39ht_hash(const HashTable *table, const Object *key) {
40 uint64_t hash = 0x65d9d65f6a19574f;
41 // printf("HASHING: ");
42 // display(key);
43 // printf("\n");
44 return 0;
45}
46
47static inline size_t
48ht_load_factor(const HashTable *table) {
49 return array_size(table->pairs) / array_cap(table->pairs);
50}
51
52HashTable *
53ht_init(void) {
54 HashTable *table = malloc(sizeof(HashTable));
55 table->pairs = NULL;
56 array_init(table->pairs, HT_MIN_CAP);
57 // Clear the table ensuring all references point to NULL.
58 for (size_t i = 0; i < array_cap(table->pairs); i++) {
59 table->pairs[i] = (HashTablePair){NULL, NULL};
60 }
61 table->shift_amount = HT_MIN_SHIFT;
62 return table;
63}
64
65void
66ht_insert(HashTable *table, const Object *key, const Object *value) {
67 // TODO: Grow if needed.
68 size_t position = ht_hash(table, key);
69 size_t probe_position = position;
70
71 // Verify the key in that position is free. If not, use linear probing to
72 // find the next free slot.
73 HashTablePair *pairs = table->pairs;
74 while (true) {
75 if (pairs[probe_position].key == NULL) {
76 break;
77 }
78 if (obj_eq(pairs[probe_position].key, key)) {
79 break;
80 }
81 if (probe_position == array_cap(pairs)) {
82 probe_position = 0;
83 } else {
84 probe_position++;
85 }
86 }
87 pairs[probe_position].key = (Object *)key;
88 pairs[probe_position].value = (Object *)value;
89 return;
90}
91
92Object *
93ht_lookup(const HashTable *table, const Object *key) {
94 size_t position = ht_hash(table, key);
95 size_t probe_position = position;
96
97 // Verify the key in that position is the same. If not perform linear
98 // probing to find it.
99 HashTablePair *pairs = table->pairs;
100 while (true) {
101 if (pairs[probe_position].key == NULL) {
102 return NULL;
103 }
104 if (obj_eq(pairs[probe_position].key, key)) {
105 break;
106 }
107 if (probe_position == array_cap(pairs)) {
108 probe_position = 0;
109 } else {
110 probe_position++;
111 }
112 }
113 return pairs[probe_position].value;
114}
115
116void
117ht_debug(HashTable *table) {
118 HashTablePair *pairs = table->pairs;
119 for (size_t i = 0; i < array_cap(pairs); i++) {
120 printf("i: %ld ", i);
121 if (pairs[i].key == NULL) {
122 printf("EMPTY\n");
123 } else {
124 printf("key: ");
125 display(pairs[i].key);
126 printf(" value: ");
127 display(pairs[i].value);
128 printf("\n");
129 }
130 }
131}
132
133// // Use Fibonacci hashing to map a hash to a value in range of the table.
134// static inline
135// uint64_t _fibonacci_hash(uint64_t hash, size_t shift_amount) {
136// return (hash * UINT64_C(11400714819323198485)) >> (64 - shift_amount);
137// }
138
139// // Hash a null terminated string using a circular shift + XOR hash function.
140// static inline
141// uint64_t _string_hash(const HashStash *table, const char *key) {
142// uint64_t hash = 0x65d9d65f6a19574f;
143// while (*key) {
144// hash ^= (uint64_t)*key++;
145// hash = (hash << 8) | (hash >> (64 - 8));
146// }
147// return _fibonacci_hash(hash, table->shift_amount);
148// }
149
150// // Return the key as an unsigned integer.
151// static inline
152// uint64_t _number_hash(const HashStash *table, const char *key) {
153// uint64_t hash = 0;
154// memcpy(&hash, key, table->key_length);
155// return _fibonacci_hash(hash, table->shift_amount);
156// }
157
158#endif // BDL_HASHTABLE_H
diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c
index 73a9244..1cb7c82 100755
--- a/src/bootstrap/main.c
+++ b/src/bootstrap/main.c
@@ -7,6 +7,7 @@
7#include <string.h> 7#include <string.h>
8 8
9#include "darray.h" 9#include "darray.h"
10#include "hashtable.h"
10 11
11#include "singletons.c" 12#include "singletons.c"
12 13
@@ -20,268 +21,307 @@
20#include "read_line.c" 21#include "read_line.c"
21#include "string_view.c" 22#include "string_view.c"
22 23
23void 24int main(void) {
24init(void) { 25 // Initialize GC.
25 // Initialize garbage collector. 26 gc_init();
26 init_gc(); 27
27 28 // Initialize key-value objects.
28 // Initialize singletons. 29 Object *k1 = MAKE_SYM("Alice");
29 obj_nil = alloc_object(OBJ_TYPE_NIL); 30 Object *k2 = MAKE_SYM("Bob");
30 obj_true = alloc_object(OBJ_TYPE_BOOL); 31 Object *k3 = MAKE_SYM("Dog");
31 obj_false = alloc_object(OBJ_TYPE_BOOL); 32 Object *v1 = make_fixnum(10);
32 obj_err = alloc_object(OBJ_TYPE_ERR); 33 Object *v2 = make_fixnum(49);
33 obj_quote = make_symbol((StringView){"quote", 5}); 34 Object *v3 = make_fixnum(333);
34 proc_if = alloc_object(OBJ_TYPE_ERR); 35
35 push_root(obj_nil); 36 // Initialize hash table.
36 push_root(obj_true); 37 HashTable *table = ht_init();
37 push_root(obj_false); 38
38 push_root(obj_err); 39 // Add some key-value pairs.
39 push_root(obj_quote); 40 ht_insert(table, k1, v1);
40 push_root(proc_if); 41 ht_insert(table, k2, v2);
41 42 ht_insert(table, k3, v3);
42 // Global environment. 43
43 global_env = env_create(NULL); 44 // Test lookups.
44 // TODO: make sure we create symbols and strings only once (interning 45 Object *alice_val = ht_lookup(table, k1);
45 // strings?) 46 Object *bob_val = ht_lookup(table, MAKE_SYM("Bob"));
46 push_active_env(global_env); 47 Object *dog_val = ht_lookup(table, k3);
47 48
48 // Primitive symbols. 49 if (v1 == alice_val) {
49 MAKE_ENV_VAR(global_env, "else", obj_true); 50 printf("Alice match!\n");
50 MAKE_ENV_VAR(global_env, "nil", obj_nil);
51 MAKE_ENV_VAR(global_env, "if", proc_if);
52
53 // Primitive procedures.
54 MAKE_ENV_PROC(global_env, "eval", proc_eval);
55 MAKE_ENV_PROC(global_env, "quote", proc_quote);
56 MAKE_ENV_PROC(global_env, "car", proc_car);
57 MAKE_ENV_PROC(global_env, "cdr", proc_cdr);
58 MAKE_ENV_PROC(global_env, "cons", proc_cons);
59 MAKE_ENV_PROC(global_env, "list", proc_list);
60 MAKE_ENV_PROC(global_env, "+", proc_sum);
61 MAKE_ENV_PROC(global_env, "-", proc_sub);
62 MAKE_ENV_PROC(global_env, "*", proc_mul);
63 MAKE_ENV_PROC(global_env, "/", proc_div);
64 MAKE_ENV_PROC(global_env, "%", proc_mod);
65 MAKE_ENV_PROC(global_env, "print", proc_print);
66 MAKE_ENV_PROC(global_env, "display", proc_display);
67 MAKE_ENV_PROC(global_env, "newline", proc_newline);
68 MAKE_ENV_PROC(global_env, "boolean?", proc_is_boolean);
69 MAKE_ENV_PROC(global_env, "nil?", proc_is_nil);
70 MAKE_ENV_PROC(global_env, "symbol?", proc_is_symbol);
71 MAKE_ENV_PROC(global_env, "string?", proc_is_string);
72 MAKE_ENV_PROC(global_env, "fixnum?", proc_is_fixnum);
73 MAKE_ENV_PROC(global_env, "pair?", proc_is_pair);
74 MAKE_ENV_PROC(global_env, "procedure?", proc_is_procedure);
75 MAKE_ENV_PROC(global_env, "error?", proc_is_error);
76 MAKE_ENV_PROC(global_env, "not", proc_not);
77 MAKE_ENV_PROC(global_env, "and", proc_and);
78 MAKE_ENV_PROC(global_env, "or", proc_or);
79 MAKE_ENV_PROC(global_env, "cond", proc_cond);
80 MAKE_ENV_PROC(global_env, "<", proc_num_less_than);
81 MAKE_ENV_PROC(global_env, "<=", proc_num_lesseq_than);
82 MAKE_ENV_PROC(global_env, ">", proc_num_greater_than);
83 MAKE_ENV_PROC(global_env, ">=", proc_num_greatereq_than);
84 MAKE_ENV_PROC(global_env, "=", proc_num_equal);
85 MAKE_ENV_PROC(global_env, "eq?", proc_equal);
86 MAKE_ENV_PROC(global_env, "def", proc_define);
87 MAKE_ENV_PROC(global_env, "set!", proc_set);
88 MAKE_ENV_PROC(global_env, "lambda", proc_lambda);
89 MAKE_ENV_PROC(global_env, "fun", proc_fun);
90
91 // Runtime procedures.
92 MAKE_ENV_PROC(global_env, "supress-errors", proc_supress_errors);
93}
94
95void
96process_source(const StringView *source) {
97 Token *tokens = tokenize(source);
98 if (errors_n != 0) {
99 if (tokens != NULL) {
100 array_free(tokens);
101 }
102 return;
103 }
104
105 Visitor visitor = (Visitor){
106 .tokens = tokens,
107 .current = 0,
108 };
109 while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) {
110 // Check the root node stack size before parsing
111 size_t root_stack_size = array_size(gc.roots);
112 Object *root = parse_tree(&visitor);
113 array_head(gc.roots)->size = root_stack_size;
114 if (root == obj_err || errors_n != 0) {
115 break;
116 }
117 push_root(root);
118
119 Object *result = eval(global_env, root);
120 if (result != obj_nil) {
121 display(result);
122 printf("\n");
123 }
124 pop_root();
125 } 51 }
126 52 if (v2 == bob_val) {
127 if (tokens != NULL) { 53 printf("Bob match!\n");
128 array_free(tokens);
129 }
130}
131
132#define REPL_PROMPT "bdl> "
133
134void
135run_repl(void) {
136 printf("BDL REPL (Press Ctrl-D or Ctrl-C to exit)\n");
137 while (true) {
138 printf(REPL_PROMPT);
139 StringView sv = read_line();
140 if (sv.start == NULL) {
141 return;
142 }
143 process_source(&sv);
144
145 // Check if there were any errors.
146 if (errors_n != 0 && !supress_errors) {
147 for (size_t i = 0; i < errors_n; i++) {
148 Error err = errors[i];
149 for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) {
150 putchar(' ');
151 }
152 printf("|\n");
153 for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) {
154 putchar(' ');
155 }
156 printf("%s\n", error_msgs[err.value]);
157 }
158 errors_n = 0;
159 continue;
160 }
161 }
162}
163
164void
165run_file(char *file_name) {
166 FILE *file = fopen(file_name, "r");
167 if (!file) {
168 fprintf(stderr, "error: couldn't open input file: %s\n", file_name);
169 exit(EXIT_FAILURE);
170 }
171
172 // Read entire file into memory.
173 fseek(file, 0, SEEK_END);
174 size_t file_size = ftell(file);
175 fseek(file, 0, SEEK_SET);
176
177 char *source = malloc(file_size + 1);
178 fread(source, 1, file_size, file);
179 source[file_size] = 0;
180
181 StringView sv = (StringView){
182 .start = source,
183 .n = file_size,
184 };
185
186 process_source(&sv);
187
188 // Check if there were any errors.
189 if (errors_n != 0 && !supress_errors) {
190 for (size_t i = 0; i < errors_n; i++) {
191 Error err = errors[i];
192 fprintf(stderr, "%s", file_name);
193 if (err.line != 0) {
194 fprintf(stderr, ":%ld:%ld", err.line, err.col);
195 }
196 fprintf(stderr, ": %s\n", error_msgs[err.value]);
197 }
198 errors_n = 0;
199 }
200
201 free(source);
202 fclose(file);
203}
204
205#define STDIN_BUF_CAP 16
206
207void
208run_stdin(void) {
209 size_t buf_size = 0;
210 char *source = NULL;
211 array_init(source, STDIN_BUF_CAP);
212
213 char c;
214 while ((c = getchar()) != EOF) {
215 array_push(source, c);
216 buf_size++;
217 } 54 }
218 55 if (v3 == dog_val) {
219 StringView sv = (StringView){ 56 printf("Dog match!\n");
220 .start = source,
221 .n = buf_size,
222 };
223
224 process_source(&sv);
225
226 // Check if there were any errors.
227 if (errors_n != 0 && !supress_errors) {
228 for (size_t i = 0; i < errors_n; i++) {
229 Error err = errors[i];
230 fprintf(stderr, "stdin");
231 if (err.line != 0) {
232 fprintf(stderr, ":%ld:%ld", err.line, err.col);
233 }
234 fprintf(stderr, ": %s\n", error_msgs[err.value]);
235 }
236 errors_n = 0;
237 } 57 }
238 58
239 array_free(source); 59 ht_debug(table);
240} 60 return 0;
241
242#ifndef BIN_NAME
243#define BIN_NAME "bdl"
244#endif
245
246void
247print_usage(void) {
248 printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME);
249 printf("\n");
250 printf("\t-i\tInteractive mode (REPL).\n");
251 printf("\n");
252} 61}
253 62
254int 63// void
255main(int argc, char *argv[]) { 64// init(void) {
256 init(); 65// // Initialize garbage collector.
257 66// gc_init();
258 int option; 67
259 while ((option = getopt(argc, argv, "i")) != -1) { 68// // Initialize singletons.
260 switch (option) { 69// obj_nil = alloc_object(OBJ_TYPE_NIL);
261 case 'i': { 70// obj_true = alloc_object(OBJ_TYPE_BOOL);
262 // Interactive mode. 71// obj_false = alloc_object(OBJ_TYPE_BOOL);
263 run_repl(); 72// obj_err = alloc_object(OBJ_TYPE_ERR);
264 return EXIT_SUCCESS; 73// obj_quote = make_symbol((StringView){"quote", 5});
265 } break; 74// proc_if = alloc_object(OBJ_TYPE_ERR);
266 default: { 75// push_root(obj_nil);
267 print_usage(); 76// push_root(obj_true);
268 return EXIT_FAILURE; 77// push_root(obj_false);
269 } break; 78// push_root(obj_err);
270 } 79// push_root(obj_quote);
271 } 80// push_root(proc_if);
272 81
273 // Run from stdin. 82// // Global environment.
274 if (optind == argc) { 83// global_env = env_create(NULL);
275 run_stdin(); 84// // TODO: make sure we create symbols and strings only once (interning
276 return EXIT_SUCCESS; 85// // strings?)
277 } 86// push_active_env(global_env);
278 87
279 // Run from file. 88// // Primitive symbols.
280 while (optind < argc) { 89// MAKE_ENV_VAR(global_env, "else", obj_true);
281 char *file_name = argv[optind]; 90// MAKE_ENV_VAR(global_env, "nil", obj_nil);
282 run_file(file_name); 91// MAKE_ENV_VAR(global_env, "if", proc_if);
283 optind++; 92
284 } 93// // Primitive procedures.
285 94// MAKE_ENV_PROC(global_env, "eval", proc_eval);
286 return EXIT_SUCCESS; 95// MAKE_ENV_PROC(global_env, "quote", proc_quote);
287} 96// MAKE_ENV_PROC(global_env, "car", proc_car);
97// MAKE_ENV_PROC(global_env, "cdr", proc_cdr);
98// MAKE_ENV_PROC(global_env, "cons", proc_cons);
99// MAKE_ENV_PROC(global_env, "list", proc_list);
100// MAKE_ENV_PROC(global_env, "+", proc_sum);
101// MAKE_ENV_PROC(global_env, "-", proc_sub);
102// MAKE_ENV_PROC(global_env, "*", proc_mul);
103// MAKE_ENV_PROC(global_env, "/", proc_div);
104// MAKE_ENV_PROC(global_env, "%", proc_mod);
105// MAKE_ENV_PROC(global_env, "print", proc_print);
106// MAKE_ENV_PROC(global_env, "display", proc_display);
107// MAKE_ENV_PROC(global_env, "newline", proc_newline);
108// MAKE_ENV_PROC(global_env, "boolean?", proc_is_boolean);
109// MAKE_ENV_PROC(global_env, "nil?", proc_is_nil);
110// MAKE_ENV_PROC(global_env, "symbol?", proc_is_symbol);
111// MAKE_ENV_PROC(global_env, "string?", proc_is_string);
112// MAKE_ENV_PROC(global_env, "fixnum?", proc_is_fixnum);
113// MAKE_ENV_PROC(global_env, "pair?", proc_is_pair);
114// MAKE_ENV_PROC(global_env, "procedure?", proc_is_procedure);
115// MAKE_ENV_PROC(global_env, "error?", proc_is_error);
116// MAKE_ENV_PROC(global_env, "not", proc_not);
117// MAKE_ENV_PROC(global_env, "and", proc_and);
118// MAKE_ENV_PROC(global_env, "or", proc_or);
119// MAKE_ENV_PROC(global_env, "cond", proc_cond);
120// MAKE_ENV_PROC(global_env, "<", proc_num_less_than);
121// MAKE_ENV_PROC(global_env, "<=", proc_num_lesseq_than);
122// MAKE_ENV_PROC(global_env, ">", proc_num_greater_than);
123// MAKE_ENV_PROC(global_env, ">=", proc_num_greatereq_than);
124// MAKE_ENV_PROC(global_env, "=", proc_num_equal);
125// MAKE_ENV_PROC(global_env, "eq?", proc_equal);
126// MAKE_ENV_PROC(global_env, "def", proc_define);
127// MAKE_ENV_PROC(global_env, "set!", proc_set);
128// MAKE_ENV_PROC(global_env, "lambda", proc_lambda);
129// MAKE_ENV_PROC(global_env, "fun", proc_fun);
130
131// // Runtime procedures.
132// MAKE_ENV_PROC(global_env, "supress-errors", proc_supress_errors);
133// }
134
135// void
136// process_source(const StringView *source) {
137// Token *tokens = tokenize(source);
138// if (errors_n != 0) {
139// if (tokens != NULL) {
140// array_free(tokens);
141// }
142// return;
143// }
144
145// Visitor visitor = (Visitor){
146// .tokens = tokens,
147// .current = 0,
148// };
149// while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) {
150// // Check the root node stack size before parsing
151// size_t root_stack_size = array_size(gc.roots);
152// Object *root = parse_tree(&visitor);
153// array_head(gc.roots)->size = root_stack_size;
154// if (root == obj_err || errors_n != 0) {
155// break;
156// }
157// push_root(root);
158
159// Object *result = eval(global_env, root);
160// if (result != obj_nil) {
161// display(result);
162// printf("\n");
163// }
164// pop_root();
165// }
166
167// if (tokens != NULL) {
168// array_free(tokens);
169// }
170// }
171
172// #define REPL_PROMPT "bdl> "
173
174// void
175// run_repl(void) {
176// printf("BDL REPL (Press Ctrl-D or Ctrl-C to exit)\n");
177// while (true) {
178// printf(REPL_PROMPT);
179// StringView sv = read_line();
180// if (sv.start == NULL) {
181// return;
182// }
183// process_source(&sv);
184
185// // Check if there were any errors.
186// if (errors_n != 0 && !supress_errors) {
187// for (size_t i = 0; i < errors_n; i++) {
188// Error err = errors[i];
189// for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) {
190// putchar(' ');
191// }
192// printf("|\n");
193// for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) {
194// putchar(' ');
195// }
196// printf("%s\n", error_msgs[err.value]);
197// }
198// errors_n = 0;
199// continue;
200// }
201// }
202// }
203
204// void
205// run_file(char *file_name) {
206// FILE *file = fopen(file_name, "r");
207// if (!file) {
208// fprintf(stderr, "error: couldn't open input file: %s\n", file_name);
209// exit(EXIT_FAILURE);
210// }
211
212// // Read entire file into memory.
213// fseek(file, 0, SEEK_END);
214// size_t file_size = ftell(file);
215// fseek(file, 0, SEEK_SET);
216
217// char *source = malloc(file_size + 1);
218// fread(source, 1, file_size, file);
219// source[file_size] = 0;
220
221// StringView sv = (StringView){
222// .start = source,
223// .n = file_size,
224// };
225
226// process_source(&sv);
227
228// // Check if there were any errors.
229// if (errors_n != 0 && !supress_errors) {
230// for (size_t i = 0; i < errors_n; i++) {
231// Error err = errors[i];
232// fprintf(stderr, "%s", file_name);
233// if (err.line != 0) {
234// fprintf(stderr, ":%ld:%ld", err.line, err.col);
235// }
236// fprintf(stderr, ": %s\n", error_msgs[err.value]);
237// }
238// errors_n = 0;
239// }
240
241// free(source);
242// fclose(file);
243// }
244
245// #define STDIN_BUF_CAP 16
246
247// void
248// run_stdin(void) {
249// size_t buf_size = 0;
250// char *source = NULL;
251// array_init(source, STDIN_BUF_CAP);
252
253// char c;
254// while ((c = getchar()) != EOF) {
255// array_push(source, c);
256// buf_size++;
257// }
258
259// StringView sv = (StringView){
260// .start = source,
261// .n = buf_size,
262// };
263
264// process_source(&sv);
265
266// // Check if there were any errors.
267// if (errors_n != 0 && !supress_errors) {
268// for (size_t i = 0; i < errors_n; i++) {
269// Error err = errors[i];
270// fprintf(stderr, "stdin");
271// if (err.line != 0) {
272// fprintf(stderr, ":%ld:%ld", err.line, err.col);
273// }
274// fprintf(stderr, ": %s\n", error_msgs[err.value]);
275// }
276// errors_n = 0;
277// }
278
279// array_free(source);
280// }
281
282// #ifndef BIN_NAME
283// #define BIN_NAME "bdl"
284// #endif
285
286// void
287// print_usage(void) {
288// printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME);
289// printf("\n");
290// printf("\t-i\tInteractive mode (REPL).\n");
291// printf("\n");
292// }
293
294// int
295// main(int argc, char *argv[]) {
296// init();
297
298// int option;
299// while ((option = getopt(argc, argv, "i")) != -1) {
300// switch (option) {
301// case 'i': {
302// // Interactive mode.
303// run_repl();
304// return EXIT_SUCCESS;
305// } break;
306// default: {
307// print_usage();
308// return EXIT_FAILURE;
309// } break;
310// }
311// }
312
313// // Run from stdin.
314// if (optind == argc) {
315// run_stdin();
316// return EXIT_SUCCESS;
317// }
318
319// // Run from file.
320// while (optind < argc) {
321// char *file_name = argv[optind];
322// run_file(file_name);
323// optind++;
324// }
325
326// return EXIT_SUCCESS;
327// }
diff --git a/src/bootstrap/objects.c b/src/bootstrap/objects.c
index 3ca2e43..c71bc40 100644
--- a/src/bootstrap/objects.c
+++ b/src/bootstrap/objects.c
@@ -105,7 +105,7 @@ display(Object *root) {
105} 105}
106 106
107bool 107bool
108obj_eq(Object *a, Object* b) { 108obj_eq(const Object *a, const Object* b) {
109 if (a->type != b->type) { 109 if (a->type != b->type) {
110 return false; 110 return false;
111 } 111 }
diff --git a/src/bootstrap/objects.h b/src/bootstrap/objects.h
index 5968a44..ed623eb 100644
--- a/src/bootstrap/objects.h
+++ b/src/bootstrap/objects.h
@@ -65,7 +65,7 @@ void display(Object *root);
65void display_pair(Object *root); 65void display_pair(Object *root);
66 66
67// Object comparison. 67// Object comparison.
68bool obj_eq(Object *a, Object* b); 68bool obj_eq(const Object *a, const Object* b);
69 69
70// Utility macros. 70// Utility macros.
71#define DEBUG_OBJ(MSG,OBJ) printf((MSG)); display(OBJ); printf("\n"); 71#define DEBUG_OBJ(MSG,OBJ) printf((MSG)); display(OBJ); printf("\n");