beginnings of REPL
[muddle-interpreter.git] / src / read.c
1 /*
2 Copyright (C) 2017 Keziah Wesley
3
4 You can redistribute and/or modify this file under the terms of the
5 GNU Affero General Public License as published by the Free Software
6 Foundation, either version 3 of the License, or (at your option) any
7 later version.
8
9 This file is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public
15 License along with this file. If not, see
16 <http://www.gnu.org/licenses/>.
17 */
18
19 #include "read.h"
20 #include "object.h"
21
22 #include <assert.h>
23 #include <stdio.h>
24
25 /**
26 Tokenization
27 */
28
29 // Return the number of whitespace characters at the beginning of the input.
30 static int
31 count_whitespace (const char *p)
32 {
33   for (int i = 0;; i++)
34     {
35       switch (p[i])
36         {
37         case 0:
38         case ' ':
39         case '\n':
40         case '\r':
41         case '\t':
42         case '\v':
43         case '\f':
44           break;
45         default:
46           return i;
47         }
48     }
49 }
50
51 // Return the number of characters at the beginning of the input
52 // constituting a valid PNAME.
53 // If the input ends with '\', it is incomplete, and -1 is returned.
54 static int
55 count_pname (const char *p)
56 {
57   // rule (1): valid FLOAT / FIX isn't a PNAME.
58   // Caller must try to read as number first!
59
60   // rule (2): dot can't be first
61   if (p[0] == '.')
62     return 0;
63
64   // rule (3): "if you can't type it interactively, it's only valid non-interactively"
65   // (not currently enforced; just don't give your atoms names like ^L)
66
67   for (int i = 0;; i++)
68     {
69       switch (p[i])
70         {
71           // separators end the PNAME
72           // rule (4): whitespace
73           // rule (5): special characters
74           // rule (6): brackets
75         case ' ':
76         case '\n':
77         case '\r':
78         case '\t':
79         case '\v':
80         case '\f':
81         case ',':
82         case '#':
83         case '\'':
84         case ';':
85         case '%':
86         case '(':
87         case ')':
88         case '[':
89         case ']':
90         case '<':
91         case '>':
92         case '{':
93         case '}':
94         case '"':
95         case 0:
96           return i;
97           // escape: next char becomes normal
98         case '\\':
99           if (!p[++i])
100             return -1;
101         }
102     }
103 }
104
105 /**
106 State machine
107 */
108
109 /*
110 static uint32_t obj_get_fix32(const object *o) {
111     assert(o->type == EVALTYPE_FIX32);
112     return o->v.fix32;
113 }
114 */
115
116 // stack[0..len]: objs in current list
117 // stack[len]: parent len
118 const char *
119 read_token (const char *p, reader_stack * st)
120 {
121   p += count_whitespace (p);
122   switch (p[0])
123     {
124     case '\0':
125       break;
126     case '(':
127     case '<':
128     case '[':
129       {
130         // opener: push current framelen; start new frame
131         // store child type and parent framelen in a pseudo-object together
132         evaltype type;
133         switch (p++[0])
134           {
135           case '(':
136             type = EVALTYPE_LIST;
137             break;
138           case '<':
139             type = EVALTYPE_FORM;
140             break;
141           case '[':
142             type = EVALTYPE_VECTOR;
143             break;
144           default:
145             assert (0 && "martian opener token?");
146           }
147         *--(st->pos) = (object)
148         {
149         .fix32.type = type,.fix32.rest = 0,.fix32.val = st->framelen,};
150         st->framelen = 0;
151         break;
152       }
153     case ')':
154     case '>':
155       {
156         evaltype type;
157         switch (p++[0])
158           {
159           case ')':
160             type = EVALTYPE_LIST;
161             break;
162           case '>':
163             type = EVALTYPE_FORM;
164             break;
165           default:
166             assert (0 && "martian list closer token?");
167           }
168         // build list from current stack frame
169         pool_ptr o =
170           pool_copy_array_rev ((pool_object *) st->pos, st->framelen);
171         // pop frame, push new LIST
172         st->pos += st->framelen;
173         assert (st->pos->type == type);
174         st->framelen = st->pos->fix32.val + 1;
175         // overwrite the frame marker with the collection it became
176         st->pos->list = (list_object)
177         {
178         .type = type,.rest = 0,.head = o};
179         break;
180       }
181     case ']':
182       {
183         p++;
184         // build vector from current stack frame
185         heap_ptr h = heap_copy_array_rev (st->pos, st->framelen);
186         // pop frame, push new VECTOR
187         uint32_t len = st->framelen;
188         st->pos += st->framelen;
189         assert (st->pos->type == EVALTYPE_VECTOR);
190         st->framelen = st->pos->fix32.val + 1;
191         st->pos->vector = new_vector (h, len);
192         break;
193       }
194     case '4':
195       {
196         p++;
197         // push fix obj, extending frame
198         (--(st->pos))->fix64 = new_fix64 (4);
199         st->framelen++;
200         break;
201       }
202     default:
203       fprintf (stderr, "read unimplemented for char: '%c'\n", *p);
204       assert (0 && "read unimplemented for char");
205     }
206   return p;
207 }