]> git.lizzy.rs Git - nothing.git/blob - src/script/parser.c
785809b48e8875bb4acc18cc73c3f948d6a96b70
[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 struct ParseResult parse_cdr(struct Token current_token)
8 {
9     if (*current_token.begin != '.') {
10         return parse_failure("Expected .", current_token.begin);
11     }
12
13     struct ParseResult cdr = parse_expr(next_token(current_token.end));
14     if (cdr.is_error) {
15         return cdr;
16     }
17
18     current_token = next_token(cdr.end);
19
20     if (*current_token.begin != ')') {
21         destroy_expr(cdr.expr);
22         return parse_failure("Expected )", current_token.begin);
23     }
24
25     return parse_success(cdr.expr, current_token.end);
26 }
27
28 static struct ParseResult parse_cons(struct Token current_token)
29 {
30     if (*current_token.begin != '(') {
31         return parse_failure("Expected (", current_token.begin);
32     }
33
34     current_token = next_token(current_token.end);
35
36     if (*current_token.begin == ')') {
37         return parse_success(atom_as_expr(create_symbol_atom("nil", NULL)), current_token.end);
38     }
39
40     struct ParseResult car = parse_expr(current_token);
41     if (car.is_error) {
42         return car;
43     }
44
45     struct ParseResult cdr = parse_cdr(next_token(car.end));
46     if (cdr.is_error) {
47         destroy_expr(car.expr);
48         return cdr;
49     }
50
51     return parse_success(cons_as_expr(create_cons(car.expr, cdr.expr)), cdr.end);
52 }
53
54 static struct ParseResult parse_string(struct Token current_token)
55 {
56     if (*current_token.begin != '"') {
57         return parse_failure("Expected \"", current_token.begin);
58     }
59
60     if (*(current_token.end - 1) != '"') {
61         return parse_failure("Unclosed string", current_token.begin);
62     }
63
64     if (current_token.begin + 1 == current_token.end) {
65         return parse_success(atom_as_expr(create_string_atom("", NULL)),
66                              current_token.end);
67     }
68
69     return parse_success(
70         atom_as_expr(
71             create_string_atom(current_token.begin + 1, current_token.end - 1)),
72         current_token.end);
73 }
74
75 static struct ParseResult parse_number(struct Token current_token)
76 {
77     char *endptr = 0;
78     const float x = strtof(current_token.begin, &endptr);
79
80     if (current_token.begin == endptr || current_token.end != endptr) {
81         return parse_failure("Expected number", current_token.begin);
82     }
83
84     return parse_success(
85         atom_as_expr(create_number_atom(x)),
86         current_token.end);
87 }
88
89 static struct ParseResult parse_symbol(struct Token current_token)
90 {
91     if (*current_token.begin == 0) {
92         return parse_failure("EOF", current_token.begin);
93     }
94
95     return parse_success(
96         atom_as_expr(create_symbol_atom(current_token.begin, current_token.end)),
97         current_token.end);
98 }
99
100 struct ParseResult parse_expr(struct Token current_token)
101 {
102     if (*current_token.begin == 0) {
103         return parse_failure("EOF", current_token.begin);
104     }
105
106     /* TODO(#301): parse_expr doesn't parse lists */
107
108     switch (*current_token.begin) {
109     case '(': return parse_cons(current_token);
110     /* TODO(#292): parser does not support escaped string characters */
111     case '"': return parse_string(current_token);
112     default: {}
113     }
114
115     if (isdigit(*current_token.begin)) {
116         return parse_number(current_token);
117     }
118
119     return parse_symbol(current_token);
120 }
121
122 struct ParseResult parse_success(struct Expr expr,
123                                  const char *end)
124 {
125     struct ParseResult result = {
126         .is_error = false,
127         .expr = expr,
128         .end = end
129     };
130
131     return result;
132 }
133
134 struct ParseResult parse_failure(const char *error_message,
135                                  const char *end)
136 {
137     struct ParseResult result = {
138         .is_error = true,
139         .error_message = error_message,
140         .end = end
141     };
142
143     return result;
144 }
145
146 void print_parse_error(FILE *stream,
147                        const char *str,
148                        struct ParseResult result)
149 {
150     /* TODO(#293): print_parse_error doesn't support colors */
151     /* TODO(#294): print_parse_error doesn't support multiple lines */
152     if (!result.is_error) {
153         return;
154     }
155
156     fprintf(stream, "%s\n", str);
157     for (size_t i = 0; i < (size_t) (result.end - str); ++i) {
158         fprintf(stream, " ");
159     }
160     fprintf(stream, "^\n");
161     fprintf(stream, "%s\n", result.error_message);
162 }