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