]> git.lizzy.rs Git - nothing.git/blob - src/script/parser.c
TODO(#297)
[nothing.git] / src / script / parser.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4
5 #include "script/parser.h"
6
7 static bool is_symbol_char(char x)
8 {
9     static const char forbidden_symbol_chars[] = {
10         '(', ')', '"', '\'', ';'
11     };
12     static const size_t n = sizeof(forbidden_symbol_chars) / sizeof(char);
13
14     for (size_t i = 0; i < n; ++i) {
15         if (x == forbidden_symbol_chars[i] || isspace(x)) {
16             return false;
17         }
18     }
19
20     return true;
21 }
22
23 static void skip_whitespaces(const char *str, size_t *cursor, size_t n)
24 {
25     assert(str);
26     assert(cursor);
27
28     while (*cursor < n && isspace(str[*cursor])) {
29         (*cursor)++;
30     }
31 }
32
33 struct ParseResult create_expr_from_str(const char *str,
34                                         size_t *cursor,
35                                         size_t n)
36 {
37     assert(str);
38     assert(cursor);
39
40     /* TODO(#297): create_expr_from_str doesn't parse lists */
41     /* TODO(#291): create_expr_from_str doesn't no support comments */
42
43     skip_whitespaces(str, cursor, n);
44     if (*cursor >= n) {
45         return parse_failure("EOF", *cursor);
46     }
47
48     switch (str[*cursor]) {
49     case '(': {
50         (*cursor)++;
51         struct ParseResult car = create_expr_from_str(str, cursor, n);
52         if (car.is_error) {
53             return car;
54         }
55
56         skip_whitespaces(str, cursor, n);
57         if (*cursor >= n) {
58             return parse_failure("EOF", *cursor);
59         }
60
61         if (str[*cursor] != '.') {
62             return parse_failure("Expected .", *cursor);
63         }
64         (*cursor)++;
65
66         skip_whitespaces(str, cursor, n);
67         if (*cursor >= n) {
68             return parse_failure("EOF", *cursor);
69         }
70
71         struct ParseResult cdr = create_expr_from_str(str, cursor, n);
72         if (cdr.is_error) {
73             return cdr;
74         }
75
76         skip_whitespaces(str, cursor, n);
77         if (*cursor >= n) {
78             return parse_failure("EOF", *cursor);
79         }
80
81         if (str[*cursor] != ')') {
82             return parse_failure("Expected )", *cursor);
83         }
84
85         (*cursor)++;
86
87         return parse_success(cons_as_expr(create_cons(car.expr, cdr.expr)));
88     }
89
90     case '"': {
91         /* TODO(#292): parser does not support escaped string characters */
92         const size_t str_begin = *cursor + 1;
93         size_t str_end = str_begin;
94
95         while(str_end < n && str[str_end] != '"') {
96             str_end++;
97         }
98
99         if (str_end >= n) {
100             return parse_failure("Unclosed string", str_begin);
101         }
102
103         *cursor = str_end + 1;
104
105         return parse_success(
106             atom_as_expr(
107                 create_string_atom(str + str_begin, str + str_end)));
108     }
109
110     default: {
111         if (isdigit(str[*cursor])) {
112             const char *nptr = str + *cursor;
113             char *endptr = 0;
114             const float x = strtof(nptr, &endptr);
115
116             if (nptr == endptr) {
117                 return parse_failure("Number expected", *cursor);
118             }
119
120             *cursor += (size_t) (endptr - nptr);
121
122             return parse_success(atom_as_expr(create_number_atom(x)));
123         } else if (is_symbol_char(str[*cursor])) {
124             const size_t sym_begin = *cursor;
125             size_t sym_end = sym_begin;
126
127             while (sym_end < n && is_symbol_char(str[sym_end])) {
128                 sym_end++;
129             }
130
131             *cursor = sym_end;
132
133             return parse_success(
134                 atom_as_expr(
135                     create_symbol_atom(str + sym_begin, str + sym_end)));
136         }
137     }
138     }
139
140     return parse_failure("Unexpected sequence of characters", *cursor);
141 }
142
143 struct ParseResult parse_success(struct Expr expr)
144 {
145     struct ParseResult result = {
146         .is_error = false,
147         .expr = expr
148     };
149
150     return result;
151 }
152
153 struct ParseResult parse_failure(const char *error_message,
154                                  size_t error_cursor)
155 {
156     struct ParseResult result = {
157         .is_error = true,
158         .error = {
159             .error_message = error_message,
160             .error_cursor = error_cursor
161         }
162     };
163
164     return result;
165 }
166
167 void print_parse_error(FILE *stream,
168                        const char *str,
169                        struct ParseError error)
170 {
171     /* TODO(#293): print_parse_error doesn't support colors */
172     /* TODO(#294): print_parse_error doesn't support multiple lines */
173
174     fprintf(stream, "%s\n", str);
175     for (size_t i = 0; i < error.error_cursor; ++i) {
176         fprintf(stream, " ");
177     }
178     fprintf(stream, "^\n");
179     fprintf(stream, "%s\n", error.error_message);
180 }