Line data Source code
1 : #include <assert.h>
2 : #include <ctype.h>
3 : #include <string.h>
4 : #include "libstephen/lisp.h"
5 : #include "libstephen/cb.h"
6 :
7 : typedef struct {
8 : lisp_value *result;
9 : int index;
10 : } result;
11 :
12 : result lisp_parse_value(lisp_runtime *rt, char *input, int index);
13 :
14 0 : result lisp_parse_integer(lisp_runtime *rt, char *input, int index)
15 : {
16 : //printf("lisp_parse_integer(%s, %d)\n", input, index);
17 : int n;
18 0 : lisp_integer *v = (lisp_integer*)lisp_new(rt, type_integer);
19 0 : sscanf(input + index, "%d%n", &v->x, &n);
20 0 : return (result){(lisp_value*)v, index + n};
21 : }
22 :
23 0 : char lisp_escape(char escape)
24 : {
25 0 : switch (escape) {
26 : case 'a':
27 0 : return '\a';
28 : case 'b':
29 0 : return '\b';
30 : case 'f':
31 0 : return '\f';
32 : case 'n':
33 0 : return '\n';
34 : case 'r':
35 0 : return '\b';
36 : case 't':
37 0 : return '\t';
38 : case 'v':
39 0 : return '\v';
40 : default:
41 0 : return escape;
42 : }
43 : }
44 :
45 0 : result lisp_parse_string(lisp_runtime *rt, char *input, int index)
46 : {
47 0 : int i = index + 1;
48 : cbuf cb;
49 0 : cb_init(&cb, 16);
50 0 : while (input[i] && input[i] != '"') {
51 0 : if (input[i] == '\\') {
52 0 : cb_append(&cb, lisp_escape(input[++i]));
53 : } else {
54 0 : cb_append(&cb, input[i]);
55 : }
56 0 : i++;
57 : }
58 0 : cb_trim(&cb);
59 0 : lisp_string *str = (lisp_string*)lisp_new(rt, type_string);
60 0 : str->s = cb.buf;
61 0 : return (result){(lisp_value*)str, ++i};
62 : }
63 :
64 0 : result lisp_parse_list_or_sexp(lisp_runtime *rt, char *input, int index)
65 : {
66 0 : while (isspace(input[index])) {index++;}
67 0 : if (input[index] == ')') {
68 0 : return (result){(lisp_value*)lisp_nil_new(rt), index + 1};
69 : }
70 :
71 0 : result r = lisp_parse_value(rt, input, index);
72 0 : index = r.index;
73 0 : lisp_list *rv = (lisp_list*)lisp_new(rt, type_list);
74 0 : rv->left = r.result;
75 0 : lisp_list *l = rv;
76 :
77 : while (true) {
78 0 : while (isspace(input[index])) {
79 0 : index++;
80 : }
81 :
82 0 : if (input[index] == '.') {
83 0 : index++;
84 0 : result r = lisp_parse_value(rt, input, index);
85 0 : index = r.index;
86 0 : l->right = r.result;
87 0 : return (result){(lisp_value*)rv, index};
88 0 : } else if (input[index] == ')') {
89 0 : index++;
90 0 : l->right = lisp_nil_new(rt);
91 0 : return (result){(lisp_value*)rv, index};
92 : } else {
93 0 : result r = lisp_parse_value(rt, input, index);
94 0 : l->right = lisp_new(rt, type_list);
95 0 : l = (lisp_list*)l->right;
96 0 : l->left = r.result;
97 0 : index = r.index;
98 : }
99 0 : }
100 : }
101 :
102 0 : result lisp_parse_symbol(lisp_runtime *rt, char *input, int index)
103 : {
104 0 : int n = 0;
105 0 : while (input[index + n] && !isspace(input[index + n]) &&
106 0 : input[index + n] != ')' && input[index + n] != '.' &&
107 0 : input[index + n] != '\'') {
108 0 : n++;
109 : }
110 0 : lisp_symbol *s = (lisp_symbol*)lisp_new(rt, type_symbol);
111 0 : s->sym = malloc(n + 1);
112 0 : strncpy(s->sym, input + index, n);
113 0 : s->sym[n] = '\0';
114 0 : return (result){(lisp_value*)s, index + n};
115 : }
116 :
117 0 : result lisp_parse_quote(lisp_runtime *rt, char *input, int index)
118 : {
119 0 : result r = lisp_parse_value(rt, input, index + 1);
120 0 : r.result = lisp_quote(rt, r.result);
121 0 : return r;
122 : }
123 :
124 0 : result lisp_parse_value(lisp_runtime *rt, char *input, int index)
125 : {
126 0 : while (isspace(input[index])) {
127 0 : index++;
128 : }
129 :
130 0 : if (input[index] == '"') {
131 0 : return lisp_parse_string(rt, input, index);
132 : }
133 0 : if (input[index] == '\0') {
134 0 : return (result){NULL, index};
135 : }
136 0 : if (input[index] == ')') {
137 0 : return (result){lisp_nil_new(rt), index + 1};
138 : }
139 0 : if (input[index] == '(') {
140 0 : return lisp_parse_list_or_sexp(rt, input, index + 1);
141 : }
142 0 : if (input[index] == '\'') {
143 0 : return lisp_parse_quote(rt, input, index);
144 : }
145 0 : if (isdigit(input[index])) {
146 0 : return lisp_parse_integer(rt, input, index);
147 : }
148 0 : return lisp_parse_symbol(rt, input, index);
149 : }
150 :
151 0 : lisp_value *lisp_parse(lisp_runtime *rt, char *input)
152 : {
153 0 : return lisp_parse_value(rt, input, 0).result;
154 : }
|