]> git.lizzy.rs Git - nothing.git/blob - src/script/parser.c
(#288) Extend ParseResult with error_cursor
[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: 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(#288): create_expr_from_str does not support strings */
75         return parse_failure("Strings are not supported", *cursor);
76     }
77
78     default: {
79         if (isdigit(str[*cursor])) {
80             const char *nptr = str + *cursor;
81             char *endptr = 0;
82             const double x = strtod(nptr, &endptr);
83
84             if (nptr == endptr) {
85                 return parse_failure("Number expected", *cursor);
86             }
87
88             *cursor += (size_t) (endptr - nptr);
89
90             return parse_success(atom_as_expr(create_atom(ATOM_NUMBER, x)));
91         } else if (isalpha(str[*cursor])) {
92             /* TODO(#289): create_expr_from_str does not support symbols */
93             return parse_failure("Symbols are not supported", *cursor);
94         }
95     }
96     }
97
98     return parse_failure("Unexpected sequence of characters", *cursor);
99 }
100
101 struct ParseResult parse_success(struct Expr expr)
102 {
103     struct ParseResult result = {
104         .is_error = false,
105         .expr = expr
106     };
107
108     return result;
109 }
110
111 struct ParseResult parse_failure(const char *error,
112                                  size_t error_cursor)
113 {
114     struct ParseResult result = {
115         .is_error = true,
116         .error = error,
117         .error_cursor = error_cursor
118     };
119
120     return result;
121 }
122
123 /* TODO: there is no way to create a pretty report from ParseResult in case of an error */