diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/bootstrap/main.c | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c index fad3333..241697a 100755 --- a/src/bootstrap/main.c +++ b/src/bootstrap/main.c | |||
@@ -5,6 +5,10 @@ | |||
5 | 5 | ||
6 | #include "shorthand.h" | 6 | #include "shorthand.h" |
7 | 7 | ||
8 | |||
9 | // FIXME: We are not worried right now about freeing memory, but we should in | ||
10 | // the future. | ||
11 | |||
8 | typedef struct StringView { | 12 | typedef struct StringView { |
9 | char *start; | 13 | char *start; |
10 | size_t n; | 14 | size_t n; |
@@ -93,8 +97,44 @@ tokenize(StringView sv) { | |||
93 | } | 97 | } |
94 | continue; | 98 | continue; |
95 | } break; | 99 | } break; |
100 | case '"': { | ||
101 | if (token_n != 0) { | ||
102 | fprintf(stderr, "error: string started inside symbol\n"); | ||
103 | return (Tokens){0}; | ||
104 | } | ||
105 | |||
106 | // Find end delimiter. | ||
107 | size_t string_start = i + 1; | ||
108 | size_t string_end = i + 1; | ||
109 | while (true) { | ||
110 | if (sv.start[string_end] == '"' && sv.start[string_end - 1] != '\\') { | ||
111 | break; | ||
112 | } | ||
113 | if (string_end >= sv.n) { | ||
114 | fprintf(stderr, "error: string delimiter not found\n"); | ||
115 | return (Tokens){0}; | ||
116 | } | ||
117 | string_end++; | ||
118 | } | ||
119 | |||
120 | // Push string token. | ||
121 | tokens_buf[n++] = (StringView){ | ||
122 | .start = &sv.start[string_start - 1], | ||
123 | .n = 1, | ||
124 | }; | ||
125 | tokens_buf[n++] = (StringView){ | ||
126 | .start = &sv.start[string_start], | ||
127 | .n = string_end - string_start, | ||
128 | }; | ||
129 | tokens_buf[n++] = (StringView){ | ||
130 | .start = &sv.start[string_end], | ||
131 | .n = 1, | ||
132 | }; | ||
133 | token_n = 0; | ||
134 | i += string_end - string_start + 1; | ||
135 | } break; | ||
96 | case '(': { | 136 | case '(': { |
97 | if ((i + 1 < sv.n)) { | 137 | if ((i + 1) < sv.n) { |
98 | char next_c = sv.start[i + 1]; | 138 | char next_c = sv.start[i + 1]; |
99 | if (isspace(next_c)) { | 139 | if (isspace(next_c)) { |
100 | fprintf(stderr, "error: lparen delimiter followed by space\n"); | 140 | fprintf(stderr, "error: lparen delimiter followed by space\n"); |
@@ -113,7 +153,7 @@ tokenize(StringView sv) { | |||
113 | }; | 153 | }; |
114 | } break; | 154 | } break; |
115 | case ')': { | 155 | case ')': { |
116 | if ((i + 1 < sv.n)) { | 156 | if ((i + 1) < sv.n) { |
117 | char next_c = sv.start[i + 1]; | 157 | char next_c = sv.start[i + 1]; |
118 | if ((next_c != ')' && !isspace(next_c))) { | 158 | if ((next_c != ')' && !isspace(next_c))) { |
119 | fprintf(stderr, "error: rparen delimiter within symbol name\n"); | 159 | fprintf(stderr, "error: rparen delimiter within symbol name\n"); |
@@ -227,15 +267,28 @@ make_boolean(bool b) { | |||
227 | } | 267 | } |
228 | 268 | ||
229 | Object * | 269 | Object * |
230 | make_string(const char *str, size_t n) { | 270 | make_empty_string(void) { |
231 | Object *obj = malloc(sizeof(Object)); | 271 | Object *obj = malloc(sizeof(Object)); |
232 | obj->type = OBJ_TYPE_STRING; | 272 | obj->type = OBJ_TYPE_STRING; |
233 | obj->string = malloc(sizeof(char) * n); | 273 | obj->string = NULL; |
234 | memcpy(obj->string, str, n); | 274 | obj->string_n = 0; |
235 | obj->string_n = n; | ||
236 | return obj; | 275 | return obj; |
237 | } | 276 | } |
238 | 277 | ||
278 | void | ||
279 | append_string(Object *string, StringView sv) { | ||
280 | assert(string != NULL); | ||
281 | assert(string->type == OBJ_TYPE_STRING); | ||
282 | |||
283 | if (sv.n == 0) { | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | string->string = realloc(string->string, (string->string_n + sv.n) * sizeof(char)); | ||
288 | memcpy(string->string + string->string_n, sv.start, sv.n); | ||
289 | string->string_n += sv.n; | ||
290 | } | ||
291 | |||
239 | Object * | 292 | Object * |
240 | make_symbol(const char *str, size_t n) { | 293 | make_symbol(const char *str, size_t n) { |
241 | Object *obj = malloc(sizeof(Object)); | 294 | Object *obj = malloc(sizeof(Object)); |
@@ -302,6 +355,9 @@ build_ast(Tokens *tokens) { | |||
302 | // TODO: Report error if we haven't consumed all the tokens? | 355 | // TODO: Report error if we haven't consumed all the tokens? |
303 | while (tokens->n > 0) { | 356 | while (tokens->n > 0) { |
304 | StringView *token = consume_token(tokens); | 357 | StringView *token = consume_token(tokens); |
358 | if (token == NULL) { | ||
359 | return NULL; | ||
360 | } | ||
305 | 361 | ||
306 | // OBJ_TYPE_FIXNUM | 362 | // OBJ_TYPE_FIXNUM |
307 | if (token_is_fixnum(*token)) { | 363 | if (token_is_fixnum(*token)) { |
@@ -344,6 +400,15 @@ build_ast(Tokens *tokens) { | |||
344 | return list; | 400 | return list; |
345 | } | 401 | } |
346 | 402 | ||
403 | // OBJ_TYPE_STRING | ||
404 | if (token->start[0] == '"') { | ||
405 | Object *obj = make_empty_string(); | ||
406 | token = consume_token(tokens); | ||
407 | append_string(obj, *token); | ||
408 | consume_token(tokens); | ||
409 | return obj; | ||
410 | } | ||
411 | |||
347 | // OBJ_TYPE_SYMBOL | 412 | // OBJ_TYPE_SYMBOL |
348 | return make_symbol(token->start, token->n); | 413 | return make_symbol(token->start, token->n); |
349 | } | 414 | } |