aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-08 16:11:39 +0200
committerBad Diode <bd@badd10de.dev>2021-10-08 16:11:39 +0200
commit70d3ef508e10d458b89bf1eaac7238fa61376112 (patch)
treee9aa3fefa8b11e2f746a3ca886728c279fab36b4
parent036943d920182fe2c50e00cee2c667f6686e464a (diff)
downloadbdl-70d3ef508e10d458b89bf1eaac7238fa61376112.tar.gz
bdl-70d3ef508e10d458b89bf1eaac7238fa61376112.zip
Add support for strings
-rwxr-xr-xsrc/bootstrap/main.c77
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
8typedef struct StringView { 12typedef 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
229Object * 269Object *
230make_string(const char *str, size_t n) { 270make_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
278void
279append_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
239Object * 292Object *
240make_symbol(const char *str, size_t n) { 293make_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 }