1 /*
2 * Copyright (c) 2021 Calvin Rose
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 
23 #ifndef JANET_AMALG
24 #include "features.h"
25 #include <janet.h>
26 #include "util.h"
27 #endif
28 
29 #define JANET_PARSER_DEAD 0x1
30 #define JANET_PARSER_GENERATED_ERROR 0x2
31 
32 /* Check if a character is whitespace */
is_whitespace(uint8_t c)33 static int is_whitespace(uint8_t c) {
34     return c == ' '
35            || c == '\t'
36            || c == '\n'
37            || c == '\r'
38            || c == '\0'
39            || c == '\v'
40            || c == '\f';
41 }
42 
43 /* Code generated by tools/symcharsgen.c.
44  * The table contains 256 bits, where each bit is 1
45  * if the corresponding ascii code is a symbol char, and 0
46  * if not. The upper characters are also considered symbol
47  * chars and are then checked for utf-8 compliance. */
48 static const uint32_t symchars[8] = {
49     0x00000000, 0xf7ffec72, 0xc7ffffff, 0x07fffffe,
50     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
51 };
52 
53 /* Check if a character is a valid symbol character
54  * symbol chars are A-Z, a-z, 0-9, or one of !$&*+-./:<=>@\^_| */
janet_is_symbol_char(uint8_t c)55 int janet_is_symbol_char(uint8_t c) {
56     return symchars[c >> 5] & ((uint32_t)1 << (c & 0x1F));
57 }
58 
59 /* Validate some utf8. Useful for identifiers. Only validates
60  * the encoding, does not check for valid code points (they
61  * are less well defined than the encoding). */
janet_valid_utf8(const uint8_t * str,int32_t len)62 int janet_valid_utf8(const uint8_t *str, int32_t len) {
63     int32_t i = 0;
64     int32_t j;
65     while (i < len) {
66         int32_t nexti;
67         uint8_t c = str[i];
68 
69         /* Check the number of bytes in code point */
70         if (c < 0x80) nexti = i + 1;
71         else if ((c >> 5) == 0x06) nexti = i + 2;
72         else if ((c >> 4) == 0x0E) nexti = i + 3;
73         else if ((c >> 3) == 0x1E) nexti = i + 4;
74         /* Don't allow 5 or 6 byte code points */
75         else return 0;
76 
77         /* No overflow */
78         if (nexti > len) return 0;
79 
80         /* Ensure trailing bytes are well formed (10XX XXXX) */
81         for (j = i + 1; j < nexti; j++) {
82             if ((str[j] >> 6) != 2) return 0;
83         }
84 
85         /* Check for overlong encoding */
86         if ((nexti == i + 2) && str[i] < 0xC2) return 0;
87         if ((str[i] == 0xE0) && str[i + 1] < 0xA0) return 0;
88         if ((str[i] == 0xF0) && str[i + 1] < 0x90) return 0;
89 
90         i = nexti;
91     }
92     return 1;
93 }
94 
95 /* Get hex digit from a letter */
to_hex(uint8_t c)96 static int to_hex(uint8_t c) {
97     if (c >= '0' && c <= '9') {
98         return c - '0';
99     } else if (c >= 'A' && c <= 'F') {
100         return 10 + c - 'A';
101     } else if (c >= 'a' && c <= 'f') {
102         return 10 + c - 'a';
103     } else {
104         return -1;
105     }
106 }
107 
108 typedef int (*Consumer)(JanetParser *p, JanetParseState *state, uint8_t c);
109 struct JanetParseState {
110     int32_t counter;
111     int32_t argn;
112     int flags;
113     size_t line;
114     size_t column;
115     Consumer consumer;
116 };
117 
118 /* Define a stack on the main parser struct */
119 #define DEF_PARSER_STACK(NAME, T, STACK, STACKCOUNT, STACKCAP) \
120 static void NAME(JanetParser *p, T x) { \
121     size_t oldcount = p->STACKCOUNT; \
122     size_t newcount = oldcount + 1; \
123     if (newcount > p->STACKCAP) { \
124         T *next; \
125         size_t newcap = 2 * newcount; \
126         next = janet_realloc(p->STACK, sizeof(T) * newcap); \
127         if (NULL == next) { \
128             JANET_OUT_OF_MEMORY; \
129         } \
130         p->STACK = next; \
131         p->STACKCAP = newcap; \
132     } \
133     p->STACK[oldcount] = x; \
134     p->STACKCOUNT = newcount; \
135 }
136 
DEF_PARSER_STACK(push_buf,uint8_t,buf,bufcount,bufcap)137 DEF_PARSER_STACK(push_buf, uint8_t, buf, bufcount, bufcap)
138 DEF_PARSER_STACK(push_arg, Janet, args, argcount, argcap)
139 DEF_PARSER_STACK(_pushstate, JanetParseState, states, statecount, statecap)
140 
141 #undef DEF_PARSER_STACK
142 
143 #define PFLAG_CONTAINER 0x100
144 #define PFLAG_BUFFER 0x200
145 #define PFLAG_PARENS 0x400
146 #define PFLAG_SQRBRACKETS 0x800
147 #define PFLAG_CURLYBRACKETS 0x1000
148 #define PFLAG_STRING 0x2000
149 #define PFLAG_LONGSTRING 0x4000
150 #define PFLAG_READERMAC 0x8000
151 #define PFLAG_ATSYM 0x10000
152 #define PFLAG_COMMENT 0x20000
153 #define PFLAG_TOKEN 0x40000
154 
155 static void pushstate(JanetParser *p, Consumer consumer, int flags) {
156     JanetParseState s;
157     s.counter = 0;
158     s.argn = 0;
159     s.flags = flags;
160     s.consumer = consumer;
161     s.line = p->line;
162     s.column = p->column;
163     _pushstate(p, s);
164 }
165 
popstate(JanetParser * p,Janet val)166 static void popstate(JanetParser *p, Janet val) {
167     for (;;) {
168         JanetParseState top = p->states[--p->statecount];
169         JanetParseState *newtop = p->states + p->statecount - 1;
170         /* Source mapping info */
171         if (janet_checktype(val, JANET_TUPLE)) {
172             janet_tuple_sm_line(janet_unwrap_tuple(val)) = (int32_t) top.line;
173             janet_tuple_sm_column(janet_unwrap_tuple(val)) = (int32_t) top.column;
174         }
175         if (newtop->flags & PFLAG_CONTAINER) {
176             newtop->argn++;
177             /* Keep track of number of values in the root state */
178             if (p->statecount == 1) {
179                 p->pending++;
180                 /* Root items are always wrapped in a tuple for source map info. */
181                 const Janet *tup = janet_tuple_n(&val, 1);
182                 janet_tuple_sm_line(tup) = (int32_t) top.line;
183                 janet_tuple_sm_column(tup) = (int32_t) top.column;
184                 val = janet_wrap_tuple(tup);
185             }
186             push_arg(p, val);
187             return;
188         } else if (newtop->flags & PFLAG_READERMAC) {
189             Janet *t = janet_tuple_begin(2);
190             int c = newtop->flags & 0xFF;
191             const char *which =
192                 (c == '\'') ? "quote" :
193                 (c == ',') ? "unquote" :
194                 (c == ';') ? "splice" :
195                 (c == '|') ? "short-fn" :
196                 (c == '~') ? "quasiquote" : "<unknown>";
197             t[0] = janet_csymbolv(which);
198             t[1] = val;
199             /* Quote source mapping info */
200             janet_tuple_sm_line(t) = (int32_t) newtop->line;
201             janet_tuple_sm_column(t) = (int32_t) newtop->column;
202             val = janet_wrap_tuple(janet_tuple_end(t));
203         } else {
204             return;
205         }
206     }
207 }
208 
checkescape(uint8_t c)209 static int checkescape(uint8_t c) {
210     switch (c) {
211         default:
212             return -1;
213         case 'x':
214         case 'u':
215         case 'U':
216             return 1;
217         case 'n':
218             return '\n';
219         case 't':
220             return '\t';
221         case 'r':
222             return '\r';
223         case '0':
224             return '\0';
225         case 'z':
226             return '\0';
227         case 'f':
228             return '\f';
229         case 'v':
230             return '\v';
231         case 'e':
232             return 27;
233         case '"':
234             return '"';
235         case '\\':
236             return '\\';
237     }
238 }
239 
240 /* Forward declare */
241 static int stringchar(JanetParser *p, JanetParseState *state, uint8_t c);
242 
write_codepoint(JanetParser * p,int32_t codepoint)243 static void write_codepoint(JanetParser *p, int32_t codepoint) {
244     if (codepoint <= 0x7F) {
245         push_buf(p, (uint8_t) codepoint);
246     } else if (codepoint <= 0x7FF) {
247         push_buf(p, (uint8_t)((codepoint >>  6) & 0x1F) | 0xC0);
248         push_buf(p, (uint8_t)((codepoint >>  0) & 0x3F) | 0x80);
249     } else if (codepoint <= 0xFFFF) {
250         push_buf(p, (uint8_t)((codepoint >> 12) & 0x0F) | 0xE0);
251         push_buf(p, (uint8_t)((codepoint >>  6) & 0x3F) | 0x80);
252         push_buf(p, (uint8_t)((codepoint >>  0) & 0x3F) | 0x80);
253     } else {
254         push_buf(p, (uint8_t)((codepoint >> 18) & 0x07) | 0xF0);
255         push_buf(p, (uint8_t)((codepoint >> 12) & 0x3F) | 0x80);
256         push_buf(p, (uint8_t)((codepoint >>  6) & 0x3F) | 0x80);
257         push_buf(p, (uint8_t)((codepoint >>  0) & 0x3F) | 0x80);
258     }
259 }
260 
escapeh(JanetParser * p,JanetParseState * state,uint8_t c)261 static int escapeh(JanetParser *p, JanetParseState *state, uint8_t c) {
262     int digit = to_hex(c);
263     if (digit < 0) {
264         p->error = "invalid hex digit in hex escape";
265         return 1;
266     }
267     state->argn = (state->argn << 4) + digit;
268     state->counter--;
269     if (!state->counter) {
270         push_buf(p, (uint8_t)(state->argn & 0xFF));
271         state->argn = 0;
272         state->consumer = stringchar;
273     }
274     return 1;
275 }
276 
escapeu(JanetParser * p,JanetParseState * state,uint8_t c)277 static int escapeu(JanetParser *p, JanetParseState *state, uint8_t c) {
278     int digit = to_hex(c);
279     if (digit < 0) {
280         p->error = "invalid hex digit in unicode escape";
281         return 1;
282     }
283     state->argn = (state->argn << 4) + digit;
284     state->counter--;
285     if (!state->counter) {
286         if (state->argn > 0x10FFFF) {
287             p->error = "invalid unicode codepoint";
288             return 1;
289         }
290         write_codepoint(p, state->argn);
291         state->argn = 0;
292         state->consumer = stringchar;
293     }
294     return 1;
295 }
296 
escape1(JanetParser * p,JanetParseState * state,uint8_t c)297 static int escape1(JanetParser *p, JanetParseState *state, uint8_t c) {
298     int e = checkescape(c);
299     if (e < 0) {
300         p->error = "invalid string escape sequence";
301         return 1;
302     }
303     if (c == 'x') {
304         state->counter = 2;
305         state->argn = 0;
306         state->consumer = escapeh;
307     } else if (c == 'u' || c == 'U') {
308         state->counter = c == 'u' ? 4 : 6;
309         state->argn = 0;
310         state->consumer = escapeu;
311     } else {
312         push_buf(p, (uint8_t) e);
313         state->consumer = stringchar;
314     }
315     return 1;
316 }
317 
stringend(JanetParser * p,JanetParseState * state)318 static int stringend(JanetParser *p, JanetParseState *state) {
319     Janet ret;
320     uint8_t *bufstart = p->buf;
321     int32_t buflen = (int32_t) p->bufcount;
322     if (state->flags & PFLAG_LONGSTRING) {
323         /* Post process to remove leading whitespace */
324         JanetParseState top = p->states[p->statecount - 1];
325         int32_t indent_col = (int32_t) top.column - 1;
326         uint8_t *r = bufstart, *end = r + buflen;
327         /* Check if there are any characters before the start column -
328          * if so, do not reindent. */
329         int reindent = 1;
330         while (reindent && (r < end)) {
331             if (*r++ == '\n') {
332                 for (int32_t j = 0; (r < end) && (*r != '\n') && (j < indent_col); j++, r++) {
333                     if (*r != ' ') {
334                         reindent = 0;
335                         break;
336                     }
337                 }
338             }
339         }
340         /* Now reindent if able to, otherwise just drop leading newline. */
341         if (!reindent) {
342             if (buflen > 0 && bufstart[0] == '\n') {
343                 buflen--;
344                 bufstart++;
345             }
346         } else {
347             uint8_t *w = bufstart;
348             r = bufstart;
349             while (r < end) {
350                 if (*r == '\n') {
351                     if (r == bufstart) {
352                         /* Skip leading newline */
353                         r++;
354                     } else {
355                         *w++ = *r++;
356                     }
357                     for (int32_t j = 0; (r < end) && (*r != '\n') && (j < indent_col); j++, r++);
358                 } else {
359                     *w++ = *r++;
360                 }
361             }
362             buflen = (int32_t)(w - bufstart);
363         }
364         /* Check for trailing newline character so we can remove it */
365         if (buflen > 0 && bufstart[buflen - 1] == '\n') {
366             buflen--;
367         }
368     }
369     if (state->flags & PFLAG_BUFFER) {
370         JanetBuffer *b = janet_buffer(buflen);
371         janet_buffer_push_bytes(b, bufstart, buflen);
372         ret = janet_wrap_buffer(b);
373     } else {
374         ret = janet_wrap_string(janet_string(bufstart, buflen));
375     }
376     p->bufcount = 0;
377     popstate(p, ret);
378     return 1;
379 }
380 
stringchar(JanetParser * p,JanetParseState * state,uint8_t c)381 static int stringchar(JanetParser *p, JanetParseState *state, uint8_t c) {
382     /* Enter escape */
383     if (c == '\\') {
384         state->consumer = escape1;
385         return 1;
386     }
387     /* String end */
388     if (c == '"') {
389         return stringend(p, state);
390     }
391     /* normal char */
392     if (c != '\n' && c != '\r')
393         push_buf(p, c);
394     return 1;
395 }
396 
397 /* Check for string equality in the buffer */
check_str_const(const char * cstr,const uint8_t * str,int32_t len)398 static int check_str_const(const char *cstr, const uint8_t *str, int32_t len) {
399     int32_t index;
400     for (index = 0; index < len; index++) {
401         uint8_t c = str[index];
402         uint8_t k = ((const uint8_t *)cstr)[index];
403         if (c < k) return -1;
404         if (c > k) return 1;
405         if (k == '\0') break;
406     }
407     return (cstr[index] == '\0') ? 0 : -1;
408 }
409 
tokenchar(JanetParser * p,JanetParseState * state,uint8_t c)410 static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) {
411     Janet ret;
412     double numval;
413     int32_t blen;
414     if (janet_is_symbol_char(c)) {
415         push_buf(p, (uint8_t) c);
416         if (c > 127) state->argn = 1; /* Use to indicate non ascii */
417         return 1;
418     }
419     /* Token finished */
420     blen = (int32_t) p->bufcount;
421     int start_dig = p->buf[0] >= '0' && p->buf[0] <= '9';
422     int start_num = start_dig || p->buf[0] == '-' || p->buf[0] == '+' || p->buf[0] == '.';
423     if (p->buf[0] == ':') {
424         /* Don't do full utf-8 check unless we have seen non ascii characters. */
425         int valid = (!state->argn) || janet_valid_utf8(p->buf + 1, blen - 1);
426         if (!valid) {
427             p->error = "invalid utf-8 in keyword";
428             return 0;
429         }
430         ret = janet_keywordv(p->buf + 1, blen - 1);
431     } else if (start_num && !janet_scan_number(p->buf, blen, &numval)) {
432         ret = janet_wrap_number(numval);
433     } else if (!check_str_const("nil", p->buf, blen)) {
434         ret = janet_wrap_nil();
435     } else if (!check_str_const("false", p->buf, blen)) {
436         ret = janet_wrap_false();
437     } else if (!check_str_const("true", p->buf, blen)) {
438         ret = janet_wrap_true();
439     } else {
440         if (start_dig) {
441             p->error = "symbol literal cannot start with a digit";
442             return 0;
443         } else {
444             /* Don't do full utf-8 check unless we have seen non ascii characters. */
445             int valid = (!state->argn) || janet_valid_utf8(p->buf, blen);
446             if (!valid) {
447                 p->error = "invalid utf-8 in symbol";
448                 return 0;
449             }
450             ret = janet_symbolv(p->buf, blen);
451         }
452     }
453     p->bufcount = 0;
454     popstate(p, ret);
455     return 0;
456 }
457 
comment(JanetParser * p,JanetParseState * state,uint8_t c)458 static int comment(JanetParser *p, JanetParseState *state, uint8_t c) {
459     (void) state;
460     if (c == '\n') {
461         p->statecount--;
462         p->bufcount = 0;
463     } else {
464         push_buf(p, c);
465     }
466     return 1;
467 }
468 
close_tuple(JanetParser * p,JanetParseState * state,int32_t flag)469 static Janet close_tuple(JanetParser *p, JanetParseState *state, int32_t flag) {
470     Janet *ret = janet_tuple_begin(state->argn);
471     janet_tuple_flag(ret) |= flag;
472     for (int32_t i = state->argn - 1; i >= 0; i--)
473         ret[i] = p->args[--p->argcount];
474     return janet_wrap_tuple(janet_tuple_end(ret));
475 }
476 
close_array(JanetParser * p,JanetParseState * state)477 static Janet close_array(JanetParser *p, JanetParseState *state) {
478     JanetArray *array = janet_array(state->argn);
479     for (int32_t i = state->argn - 1; i >= 0; i--)
480         array->data[i] = p->args[--p->argcount];
481     array->count = state->argn;
482     return janet_wrap_array(array);
483 }
484 
close_struct(JanetParser * p,JanetParseState * state)485 static Janet close_struct(JanetParser *p, JanetParseState *state) {
486     JanetKV *st = janet_struct_begin(state->argn >> 1);
487     for (size_t i = p->argcount - state->argn; i < p->argcount; i += 2) {
488         Janet key = p->args[i];
489         Janet value = p->args[i + 1];
490         janet_struct_put(st, key, value);
491     }
492     p->argcount -= state->argn;
493     return janet_wrap_struct(janet_struct_end(st));
494 }
495 
close_table(JanetParser * p,JanetParseState * state)496 static Janet close_table(JanetParser *p, JanetParseState *state) {
497     JanetTable *table = janet_table(state->argn >> 1);
498     for (size_t i = p->argcount - state->argn; i < p->argcount; i += 2) {
499         Janet key = p->args[i];
500         Janet value = p->args[i + 1];
501         janet_table_put(table, key, value);
502     }
503     p->argcount -= state->argn;
504     return janet_wrap_table(table);
505 }
506 
507 #define PFLAG_INSTRING 0x100000
508 #define PFLAG_END_CANDIDATE 0x200000
longstring(JanetParser * p,JanetParseState * state,uint8_t c)509 static int longstring(JanetParser *p, JanetParseState *state, uint8_t c) {
510     if (state->flags & PFLAG_INSTRING) {
511         /* We are inside the long string */
512         if (c == '`') {
513             state->flags |= PFLAG_END_CANDIDATE;
514             state->flags &= ~PFLAG_INSTRING;
515             state->counter = 1; /* Use counter to keep track of number of '=' seen */
516             return 1;
517         }
518         push_buf(p, c);
519         return 1;
520     } else if (state->flags & PFLAG_END_CANDIDATE) {
521         int i;
522         /* We are checking a potential end of the string */
523         if (state->counter == state->argn) {
524             stringend(p, state);
525             return 0;
526         }
527         if (c == '`' && state->counter < state->argn) {
528             state->counter++;
529             return 1;
530         }
531         /* Failed end candidate */
532         for (i = 0; i < state->counter; i++) {
533             push_buf(p, '`');
534         }
535         push_buf(p, c);
536         state->counter = 0;
537         state->flags &= ~PFLAG_END_CANDIDATE;
538         state->flags |= PFLAG_INSTRING;
539         return 1;
540     } else {
541         /* We are at beginning of string */
542         state->argn++;
543         if (c != '`') {
544             state->flags |= PFLAG_INSTRING;
545             push_buf(p, c);
546         }
547         return 1;
548     }
549 }
550 
551 static int root(JanetParser *p, JanetParseState *state, uint8_t c);
552 
atsign(JanetParser * p,JanetParseState * state,uint8_t c)553 static int atsign(JanetParser *p, JanetParseState *state, uint8_t c) {
554     (void) state;
555     p->statecount--;
556     switch (c) {
557         case '{':
558             pushstate(p, root, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS | PFLAG_ATSYM);
559             return 1;
560         case '"':
561             pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
562             return 1;
563         case '`':
564             pushstate(p, longstring, PFLAG_BUFFER | PFLAG_LONGSTRING);
565             return 1;
566         case '[':
567             pushstate(p, root, PFLAG_CONTAINER | PFLAG_SQRBRACKETS | PFLAG_ATSYM);
568             return 1;
569         case '(':
570             pushstate(p, root, PFLAG_CONTAINER | PFLAG_PARENS | PFLAG_ATSYM);
571             return 1;
572         default:
573             break;
574     }
575     pushstate(p, tokenchar, PFLAG_TOKEN);
576     push_buf(p, '@'); /* Push the leading at-sign that was dropped */
577     return 0;
578 }
579 
580 /* The root state of the parser */
root(JanetParser * p,JanetParseState * state,uint8_t c)581 static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
582     switch (c) {
583         default:
584             if (is_whitespace(c)) return 1;
585             if (!janet_is_symbol_char(c)) {
586                 p->error = "unexpected character";
587                 return 1;
588             }
589             pushstate(p, tokenchar, PFLAG_TOKEN);
590             return 0;
591         case '\'':
592         case ',':
593         case ';':
594         case '~':
595         case '|':
596             pushstate(p, root, PFLAG_READERMAC | c);
597             return 1;
598         case '"':
599             pushstate(p, stringchar, PFLAG_STRING);
600             return 1;
601         case '#':
602             pushstate(p, comment, PFLAG_COMMENT);
603             return 1;
604         case '@':
605             pushstate(p, atsign, PFLAG_ATSYM);
606             return 1;
607         case '`':
608             pushstate(p, longstring, PFLAG_LONGSTRING);
609             return 1;
610         case ')':
611         case ']':
612         case '}': {
613             Janet ds;
614             if (p->statecount == 1) {
615                 p->error = "unexpected delimiter";
616                 return 1;
617             }
618             if ((c == ')' && (state->flags & PFLAG_PARENS)) ||
619                     (c == ']' && (state->flags & PFLAG_SQRBRACKETS))) {
620                 if (state->flags & PFLAG_ATSYM) {
621                     ds = close_array(p, state);
622                 } else {
623                     ds = close_tuple(p, state, c == ']' ? JANET_TUPLE_FLAG_BRACKETCTOR : 0);
624                 }
625             } else if (c == '}' && (state->flags & PFLAG_CURLYBRACKETS)) {
626                 if (state->argn & 1) {
627                     p->error = "struct and table literals expect even number of arguments";
628                     return 1;
629                 }
630                 if (state->flags & PFLAG_ATSYM) {
631                     ds = close_table(p, state);
632                 } else {
633                     ds = close_struct(p, state);
634                 }
635             } else {
636                 p->error = "mismatched delimiter";
637                 return 1;
638             }
639             popstate(p, ds);
640         }
641         return 1;
642         case '(':
643             pushstate(p, root, PFLAG_CONTAINER | PFLAG_PARENS);
644             return 1;
645         case '[':
646             pushstate(p, root, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
647             return 1;
648         case '{':
649             pushstate(p, root, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
650             return 1;
651     }
652 }
653 
janet_parser_checkdead(JanetParser * parser)654 static void janet_parser_checkdead(JanetParser *parser) {
655     if (parser->flag) janet_panic("parser is dead, cannot consume");
656     if (parser->error) janet_panic("parser has unchecked error, cannot consume");
657 }
658 
659 /* Public API */
660 
janet_parser_consume(JanetParser * parser,uint8_t c)661 void janet_parser_consume(JanetParser *parser, uint8_t c) {
662     int consumed = 0;
663     janet_parser_checkdead(parser);
664     if (c == '\r') {
665         parser->line++;
666         parser->column = 0;
667     } else if (c == '\n') {
668         parser->column = 0;
669         if (parser->lookback != '\r')
670             parser->line++;
671     } else {
672         parser->column++;
673     }
674     while (!consumed && !parser->error) {
675         JanetParseState *state = parser->states + parser->statecount - 1;
676         consumed = state->consumer(parser, state, c);
677     }
678     parser->lookback = c;
679 }
680 
janet_parser_eof(JanetParser * parser)681 void janet_parser_eof(JanetParser *parser) {
682     janet_parser_checkdead(parser);
683     size_t oldcolumn = parser->column;
684     size_t oldline = parser->line;
685     janet_parser_consume(parser, '\n');
686     if (parser->statecount > 1) {
687         JanetParseState *s = parser->states + (parser->statecount - 1);
688         JanetBuffer *buffer = janet_buffer(40);
689         janet_buffer_push_cstring(buffer, "unexpected end of source, ");
690         if (s->flags & PFLAG_PARENS) {
691             janet_buffer_push_u8(buffer, '(');
692         } else if (s->flags & PFLAG_SQRBRACKETS) {
693             janet_buffer_push_u8(buffer, '[');
694         } else if (s->flags & PFLAG_CURLYBRACKETS) {
695             janet_buffer_push_u8(buffer, '{');
696         } else if (s->flags & PFLAG_STRING) {
697             janet_buffer_push_u8(buffer, '"');
698         } else if (s->flags & PFLAG_LONGSTRING) {
699             int32_t i;
700             for (i = 0; i < s->argn; i++) {
701                 janet_buffer_push_u8(buffer, '`');
702             }
703         }
704         janet_formatb(buffer, " opened at line %d, column %d", s->line, s->column);
705         parser->error = (const char *) janet_string(buffer->data, buffer->count);
706         parser->flag |= JANET_PARSER_GENERATED_ERROR;
707     }
708     parser->line = oldline;
709     parser->column = oldcolumn;
710     parser->flag |= JANET_PARSER_DEAD;
711 }
712 
janet_parser_status(JanetParser * parser)713 enum JanetParserStatus janet_parser_status(JanetParser *parser) {
714     if (parser->error) return JANET_PARSE_ERROR;
715     if (parser->flag) return JANET_PARSE_DEAD;
716     if (parser->statecount > 1) return JANET_PARSE_PENDING;
717     return JANET_PARSE_ROOT;
718 }
719 
janet_parser_flush(JanetParser * parser)720 void janet_parser_flush(JanetParser *parser) {
721     parser->argcount = 0;
722     parser->statecount = 1;
723     parser->bufcount = 0;
724     parser->pending = 0;
725 }
726 
janet_parser_error(JanetParser * parser)727 const char *janet_parser_error(JanetParser *parser) {
728     enum JanetParserStatus status = janet_parser_status(parser);
729     if (status == JANET_PARSE_ERROR) {
730         const char *e = parser->error;
731         parser->error = NULL;
732         parser->flag &= ~JANET_PARSER_GENERATED_ERROR;
733         janet_parser_flush(parser);
734         return e;
735     }
736     return NULL;
737 }
738 
janet_parser_produce(JanetParser * parser)739 Janet janet_parser_produce(JanetParser *parser) {
740     Janet ret;
741     size_t i;
742     if (parser->pending == 0) return janet_wrap_nil();
743     ret = janet_unwrap_tuple(parser->args[0])[0];
744     for (i = 1; i < parser->argcount; i++) {
745         parser->args[i - 1] = parser->args[i];
746     }
747     parser->pending--;
748     parser->argcount--;
749     parser->states[0].argn--;
750     return ret;
751 }
752 
janet_parser_produce_wrapped(JanetParser * parser)753 Janet janet_parser_produce_wrapped(JanetParser *parser) {
754     Janet ret;
755     size_t i;
756     if (parser->pending == 0) return janet_wrap_nil();
757     ret = parser->args[0];
758     for (i = 1; i < parser->argcount; i++) {
759         parser->args[i - 1] = parser->args[i];
760     }
761     parser->pending--;
762     parser->argcount--;
763     parser->states[0].argn--;
764     return ret;
765 }
766 
janet_parser_init(JanetParser * parser)767 void janet_parser_init(JanetParser *parser) {
768     parser->args = NULL;
769     parser->states = NULL;
770     parser->buf = NULL;
771     parser->argcount = 0;
772     parser->argcap = 0;
773     parser->bufcount = 0;
774     parser->bufcap = 0;
775     parser->statecount = 0;
776     parser->statecap = 0;
777     parser->error = NULL;
778     parser->lookback = -1;
779     parser->line = 1;
780     parser->column = 0;
781     parser->pending = 0;
782     parser->flag = 0;
783 
784     pushstate(parser, root, PFLAG_CONTAINER);
785 }
786 
janet_parser_deinit(JanetParser * parser)787 void janet_parser_deinit(JanetParser *parser) {
788     janet_free(parser->args);
789     janet_free(parser->buf);
790     janet_free(parser->states);
791 }
792 
janet_parser_clone(const JanetParser * src,JanetParser * dest)793 void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
794     /* Misc fields */
795     dest->flag = src->flag;
796     dest->pending = src->pending;
797     dest->lookback = src->lookback;
798     dest->line = src->line;
799     dest->column = src->column;
800     dest->error = src->error;
801 
802     /* Keep counts */
803     dest->argcount = src->argcount;
804     dest->bufcount = src->bufcount;
805     dest->statecount = src->statecount;
806 
807     /* Capacities are equal to counts */
808     dest->bufcap = dest->bufcount;
809     dest->statecap = dest->statecount;
810     dest->argcap = dest->argcount;
811 
812     /* Deep cloned fields */
813     dest->args = NULL;
814     dest->states = NULL;
815     dest->buf = NULL;
816     if (dest->bufcap) {
817         dest->buf = janet_malloc(dest->bufcap);
818         if (!dest->buf) goto nomem;
819         memcpy(dest->buf, src->buf, dest->bufcap);
820     }
821     if (dest->argcap) {
822         dest->args = janet_malloc(sizeof(Janet) * dest->argcap);
823         if (!dest->args) goto nomem;
824         memcpy(dest->args, src->args, dest->argcap * sizeof(Janet));
825     }
826     if (dest->statecap) {
827         dest->states = janet_malloc(sizeof(JanetParseState) * dest->statecap);
828         if (!dest->states) goto nomem;
829         memcpy(dest->states, src->states, dest->statecap * sizeof(JanetParseState));
830     }
831 
832     return;
833 
834 nomem:
835     JANET_OUT_OF_MEMORY;
836 }
837 
janet_parser_has_more(JanetParser * parser)838 int janet_parser_has_more(JanetParser *parser) {
839     return !!parser->pending;
840 }
841 
842 /* C functions */
843 
parsermark(void * p,size_t size)844 static int parsermark(void *p, size_t size) {
845     size_t i;
846     JanetParser *parser = (JanetParser *)p;
847     (void) size;
848     for (i = 0; i < parser->argcount; i++) {
849         janet_mark(parser->args[i]);
850     }
851     if (parser->flag & JANET_PARSER_GENERATED_ERROR) {
852         janet_mark(janet_wrap_string((const uint8_t *) parser->error));
853     }
854     return 0;
855 }
856 
parsergc(void * p,size_t size)857 static int parsergc(void *p, size_t size) {
858     JanetParser *parser = (JanetParser *)p;
859     (void) size;
860     janet_parser_deinit(parser);
861     return 0;
862 }
863 
864 static int parserget(void *p, Janet key, Janet *out);
865 static Janet parsernext(void *p, Janet key);
866 
867 const JanetAbstractType janet_parser_type = {
868     "core/parser",
869     parsergc,
870     parsermark,
871     parserget,
872     NULL, /* put */
873     NULL, /* marshal */
874     NULL, /* unmarshal */
875     NULL, /* tostring */
876     NULL, /* compare */
877     NULL, /* hash */
878     parsernext,
879     JANET_ATEND_NEXT
880 };
881 
882 /* C Function parser */
883 JANET_CORE_FN(cfun_parse_parser,
884               "(parser/new)",
885               "Creates and returns a new parser object. Parsers are state machines "
886               "that can receive bytes, and generate a stream of values.") {
887     (void) argv;
888     janet_fixarity(argc, 0);
889     JanetParser *p = janet_abstract(&janet_parser_type, sizeof(JanetParser));
890     janet_parser_init(p);
891     return janet_wrap_abstract(p);
892 }
893 
894 JANET_CORE_FN(cfun_parse_consume,
895               "(parser/consume parser bytes &opt index)",
896               "Input bytes into the parser and parse them. Will not throw errors "
897               "if there is a parse error. Starts at the byte index given by index. Returns "
898               "the number of bytes read.") {
899     janet_arity(argc, 2, 3);
900     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
901     JanetByteView view = janet_getbytes(argv, 1);
902     if (argc == 3) {
903         int32_t offset = janet_getinteger(argv, 2);
904         if (offset < 0 || offset > view.len)
905             janet_panicf("invalid offset %d out of range [0,%d]", offset, view.len);
906         view.len -= offset;
907         view.bytes += offset;
908     }
909     int32_t i;
910     for (i = 0; i < view.len; i++) {
911         janet_parser_consume(p, view.bytes[i]);
912         switch (janet_parser_status(p)) {
913             case JANET_PARSE_ROOT:
914             case JANET_PARSE_PENDING:
915                 break;
916             default:
917                 return janet_wrap_integer(i + 1);
918         }
919     }
920     return janet_wrap_integer(i);
921 }
922 
923 JANET_CORE_FN(cfun_parse_eof,
924               "(parser/eof parser)",
925               "Indicate that the end of file was reached to the parser. This puts the parser in the :dead state.") {
926     janet_fixarity(argc, 1);
927     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
928     janet_parser_eof(p);
929     return argv[0];
930 }
931 
932 JANET_CORE_FN(cfun_parse_insert,
933               "(parser/insert parser value)",
934               "Insert a value into the parser. This means that the parser state can be manipulated "
935               "in between chunks of bytes. This would allow a user to add extra elements to arrays "
936               "and tuples, for example. Returns the parser.") {
937     janet_fixarity(argc, 2);
938     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
939     JanetParseState *s = p->states + p->statecount - 1;
940     if (s->consumer == tokenchar) {
941         janet_parser_consume(p, ' ');
942         p->column--;
943         s = p->states + p->statecount - 1;
944     }
945     if (s->flags & PFLAG_COMMENT) s--;
946     if (s->flags & PFLAG_CONTAINER) {
947         s->argn++;
948         if (p->statecount == 1) {
949             p->pending++;
950             Janet tup = janet_wrap_tuple(janet_tuple_n(argv + 1, 1));
951             push_arg(p, tup);
952         } else {
953             push_arg(p, argv[1]);
954         }
955     } else if (s->flags & (PFLAG_STRING | PFLAG_LONGSTRING)) {
956         const uint8_t *str = janet_to_string(argv[1]);
957         int32_t slen = janet_string_length(str);
958         size_t newcount = p->bufcount + slen;
959         if (p->bufcap < newcount) {
960             size_t newcap = 2 * newcount;
961             p->buf = janet_realloc(p->buf, newcap);
962             if (p->buf == NULL) {
963                 JANET_OUT_OF_MEMORY;
964             }
965             p->bufcap = newcap;
966         }
967         safe_memcpy(p->buf + p->bufcount, str, slen);
968         p->bufcount = newcount;
969     } else {
970         janet_panic("cannot insert value into parser");
971     }
972     return argv[0];
973 }
974 
975 JANET_CORE_FN(cfun_parse_has_more,
976               "(parser/has-more parser)",
977               "Check if the parser has more values in the value queue.") {
978     janet_fixarity(argc, 1);
979     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
980     return janet_wrap_boolean(janet_parser_has_more(p));
981 }
982 
983 JANET_CORE_FN(cfun_parse_byte,
984               "(parser/byte parser b)",
985               "Input a single byte into the parser byte stream. Returns the parser.") {
986     janet_fixarity(argc, 2);
987     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
988     int32_t i = janet_getinteger(argv, 1);
989     janet_parser_consume(p, 0xFF & i);
990     return argv[0];
991 }
992 
993 JANET_CORE_FN(cfun_parse_status,
994               "(parser/status parser)",
995               "Gets the current status of the parser state machine. The status will "
996               "be one of:\n\n"
997               "* :pending - a value is being parsed.\n\n"
998               "* :error - a parsing error was encountered.\n\n"
999               "* :root - the parser can either read more values or safely terminate.") {
1000     janet_fixarity(argc, 1);
1001     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1002     const char *stat = NULL;
1003     switch (janet_parser_status(p)) {
1004         case JANET_PARSE_PENDING:
1005             stat = "pending";
1006             break;
1007         case JANET_PARSE_ERROR:
1008             stat = "error";
1009             break;
1010         case JANET_PARSE_ROOT:
1011             stat = "root";
1012             break;
1013         case JANET_PARSE_DEAD:
1014             stat = "dead";
1015             break;
1016     }
1017     return janet_ckeywordv(stat);
1018 }
1019 
1020 JANET_CORE_FN(cfun_parse_error,
1021               "(parser/error parser)",
1022               "If the parser is in the error state, returns the message associated with "
1023               "that error. Otherwise, returns nil. Also flushes the parser state and parser "
1024               "queue, so be sure to handle everything in the queue before calling "
1025               "parser/error.") {
1026     janet_fixarity(argc, 1);
1027     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1028     const char *err = janet_parser_error(p);
1029     if (err) {
1030         return (p->flag & JANET_PARSER_GENERATED_ERROR)
1031                ? janet_wrap_string((const uint8_t *) err)
1032                : janet_cstringv(err);
1033     }
1034     return janet_wrap_nil();
1035 }
1036 
1037 JANET_CORE_FN(cfun_parse_produce,
1038               "(parser/produce parser &opt wrap)",
1039               "Dequeue the next value in the parse queue. Will return nil if "
1040               "no parsed values are in the queue, otherwise will dequeue the "
1041               "next value. If `wrap` is truthy, will return a 1-element tuple that "
1042               "wraps the result. This tuple can be used for source-mapping "
1043               "purposes.") {
1044     janet_arity(argc, 1, 2);
1045     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1046     if (argc == 2 && janet_truthy(argv[1])) {
1047         return janet_parser_produce_wrapped(p);
1048     } else {
1049         return janet_parser_produce(p);
1050     }
1051 }
1052 
1053 JANET_CORE_FN(cfun_parse_flush,
1054               "(parser/flush parser)",
1055               "Clears the parser state and parse queue. Can be used to reset the parser "
1056               "if an error was encountered. Does not reset the line and column counter, so "
1057               "to begin parsing in a new context, create a new parser.") {
1058     janet_fixarity(argc, 1);
1059     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1060     janet_parser_flush(p);
1061     return argv[0];
1062 }
1063 
1064 JANET_CORE_FN(cfun_parse_where,
1065               "(parser/where parser &opt line col)",
1066               "Returns the current line number and column of the parser's internal state. If line is "
1067               "provided, the current line number of the parser is first set to that value. If column is "
1068               "also provided, the current column number of the parser is also first set to that value.") {
1069     janet_arity(argc, 1, 3);
1070     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1071     if (argc > 1) {
1072         int32_t line = janet_getinteger(argv, 1);
1073         if (line < 1)
1074             janet_panicf("invalid line number %d", line);
1075         p->line = (size_t) line;
1076     }
1077     if (argc > 2) {
1078         int32_t column = janet_getinteger(argv, 2);
1079         if (column < 0)
1080             janet_panicf("invalid column number %d", column);
1081         p->column = (size_t) column;
1082     }
1083     Janet *tup = janet_tuple_begin(2);
1084     tup[0] = janet_wrap_integer(p->line);
1085     tup[1] = janet_wrap_integer(p->column);
1086     return janet_wrap_tuple(janet_tuple_end(tup));
1087 }
1088 
janet_wrap_parse_state(JanetParseState * s,Janet * args,uint8_t * buff,uint32_t bufcount)1089 static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args,
1090                                     uint8_t *buff, uint32_t bufcount) {
1091     JanetTable *state = janet_table(0);
1092     const uint8_t *buffer;
1093     int add_buffer = 0;
1094     const char *type = NULL;
1095 
1096     if (s->flags & PFLAG_CONTAINER) {
1097         JanetArray *container_args = janet_array(s->argn);
1098         for (int32_t i = 0; i < s->argn; i++) {
1099             janet_array_push(container_args, args[i]);
1100         }
1101         janet_table_put(state, janet_ckeywordv("args"),
1102                         janet_wrap_array(container_args));
1103     }
1104 
1105     if (s->flags & PFLAG_PARENS || s->flags & PFLAG_SQRBRACKETS) {
1106         if (s->flags & PFLAG_ATSYM) {
1107             type = "array";
1108         } else {
1109             type = "tuple";
1110         }
1111     } else if (s->flags & PFLAG_CURLYBRACKETS) {
1112         if (s->flags & PFLAG_ATSYM) {
1113             type = "table";
1114         } else {
1115             type = "struct";
1116         }
1117     } else if (s->flags & PFLAG_STRING || s->flags & PFLAG_LONGSTRING) {
1118         if (s->flags & PFLAG_BUFFER) {
1119             type = "buffer";
1120         } else {
1121             type = "string";
1122         }
1123         add_buffer = 1;
1124     } else if (s->flags & PFLAG_COMMENT) {
1125         type = "comment";
1126         add_buffer = 1;
1127     } else if (s->flags & PFLAG_TOKEN) {
1128         type = "token";
1129         add_buffer = 1;
1130     } else if (s->flags & PFLAG_ATSYM) {
1131         type = "at";
1132     } else if (s->flags & PFLAG_READERMAC) {
1133         int c = s->flags & 0xFF;
1134         type = (c == '\'') ? "quote" :
1135                (c == ',') ? "unquote" :
1136                (c == ';') ? "splice" :
1137                (c == '~') ? "quasiquote" : "<reader>";
1138     } else {
1139         type = "root";
1140     }
1141 
1142     if (type) {
1143         janet_table_put(state, janet_ckeywordv("type"),
1144                         janet_ckeywordv(type));
1145     }
1146 
1147     if (add_buffer) {
1148         buffer = janet_string(buff, bufcount);
1149         janet_table_put(state, janet_ckeywordv("buffer"), janet_wrap_string(buffer));
1150     }
1151 
1152     janet_table_put(state, janet_ckeywordv("line"), janet_wrap_integer(s->line));
1153     janet_table_put(state, janet_ckeywordv("column"), janet_wrap_integer(s->column));
1154     return janet_wrap_table(state);
1155 }
1156 
1157 struct ParserStateGetter {
1158     const char *name;
1159     Janet(*fn)(const JanetParser *p);
1160 };
1161 
parser_state_delimiters(const JanetParser * _p)1162 static Janet parser_state_delimiters(const JanetParser *_p) {
1163     JanetParser *p = (JanetParser *)_p;
1164     size_t i;
1165     const uint8_t *str;
1166     size_t oldcount;
1167     oldcount = p->bufcount;
1168     for (i = 0; i < p->statecount; i++) {
1169         JanetParseState *s = p->states + i;
1170         if (s->flags & PFLAG_PARENS) {
1171             push_buf(p, '(');
1172         } else if (s->flags & PFLAG_SQRBRACKETS) {
1173             push_buf(p, '[');
1174         } else if (s->flags & PFLAG_CURLYBRACKETS) {
1175             push_buf(p, '{');
1176         } else if (s->flags & PFLAG_STRING) {
1177             push_buf(p, '"');
1178         } else if (s->flags & PFLAG_LONGSTRING) {
1179             int32_t i;
1180             for (i = 0; i < s->argn; i++) {
1181                 push_buf(p, '`');
1182             }
1183         }
1184     }
1185     str = janet_string(p->buf + oldcount, (int32_t)(p->bufcount - oldcount));
1186     p->bufcount = oldcount;
1187     return janet_wrap_string(str);
1188 }
1189 
parser_state_frames(const JanetParser * p)1190 static Janet parser_state_frames(const JanetParser *p) {
1191     int32_t count = (int32_t) p->statecount;
1192     JanetArray *states = janet_array(count);
1193     states->count = count;
1194     uint8_t *buf = p->buf;
1195     /* Iterate arg stack backwards */
1196     Janet *args = p->args + p->argcount;
1197     for (int32_t i = count - 1; i >= 0; --i) {
1198         JanetParseState *s = p->states + i;
1199         if (s->flags & PFLAG_CONTAINER) {
1200             args -= s->argn;
1201         }
1202         states->data[i] = janet_wrap_parse_state(s, args, buf, (uint32_t) p->bufcount);
1203     }
1204     return janet_wrap_array(states);
1205 }
1206 
1207 static const struct ParserStateGetter parser_state_getters[] = {
1208     {"frames", parser_state_frames},
1209     {"delimiters", parser_state_delimiters},
1210     {NULL, NULL}
1211 };
1212 
1213 JANET_CORE_FN(cfun_parse_state,
1214               "(parser/state parser &opt key)",
1215               "Returns a representation of the internal state of the parser. If a key is passed, "
1216               "only that information about the state is returned. Allowed keys are:\n\n"
1217               "* :delimiters - Each byte in the string represents a nested data structure. For example, "
1218               "if the parser state is '([\"', then the parser is in the middle of parsing a "
1219               "string inside of square brackets inside parentheses. Can be used to augment a REPL prompt.\n\n"
1220               "* :frames - Each table in the array represents a 'frame' in the parser state. Frames "
1221               "contain information about the start of the expression being parsed as well as the "
1222               "type of that expression and some type-specific information.") {
1223     janet_arity(argc, 1, 2);
1224     const uint8_t *key = NULL;
1225     JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type);
1226     if (argc == 2) {
1227         key = janet_getkeyword(argv, 1);
1228     }
1229 
1230     if (key) {
1231         /* Get one result */
1232         for (const struct ParserStateGetter *sg = parser_state_getters;
1233                 sg->name != NULL; sg++) {
1234             if (janet_cstrcmp(key, sg->name)) continue;
1235             return sg->fn(p);
1236         }
1237         janet_panicf("unexpected keyword %v", janet_wrap_keyword(key));
1238         return janet_wrap_nil();
1239     } else {
1240         /* Put results in table */
1241         JanetTable *tab = janet_table(0);
1242         for (const struct ParserStateGetter *sg = parser_state_getters;
1243                 sg->name != NULL; sg++) {
1244             janet_table_put(tab, janet_ckeywordv(sg->name), sg->fn(p));
1245         }
1246         return janet_wrap_table(tab);
1247     }
1248 }
1249 
1250 JANET_CORE_FN(cfun_parse_clone,
1251               "(parser/clone p)",
1252               "Creates a deep clone of a parser that is identical to the input parser. "
1253               "This cloned parser can be used to continue parsing from a good checkpoint "
1254               "if parsing later fails. Returns a new parser.") {
1255     janet_fixarity(argc, 1);
1256     JanetParser *src = janet_getabstract(argv, 0, &janet_parser_type);
1257     JanetParser *dest = janet_abstract(&janet_parser_type, sizeof(JanetParser));
1258     janet_parser_clone(src, dest);
1259     return janet_wrap_abstract(dest);
1260 }
1261 
1262 static const JanetMethod parser_methods[] = {
1263     {"byte", cfun_parse_byte},
1264     {"clone", cfun_parse_clone},
1265     {"consume", cfun_parse_consume},
1266     {"eof", cfun_parse_eof},
1267     {"error", cfun_parse_error},
1268     {"flush", cfun_parse_flush},
1269     {"has-more", cfun_parse_has_more},
1270     {"insert", cfun_parse_insert},
1271     {"produce", cfun_parse_produce},
1272     {"state", cfun_parse_state},
1273     {"status", cfun_parse_status},
1274     {"where", cfun_parse_where},
1275     {NULL, NULL}
1276 };
1277 
parserget(void * p,Janet key,Janet * out)1278 static int parserget(void *p, Janet key, Janet *out) {
1279     (void) p;
1280     if (!janet_checktype(key, JANET_KEYWORD)) return 0;
1281     return janet_getmethod(janet_unwrap_keyword(key), parser_methods, out);
1282 }
1283 
parsernext(void * p,Janet key)1284 static Janet parsernext(void *p, Janet key) {
1285     (void) p;
1286     return janet_nextmethod(parser_methods, key);
1287 }
1288 
1289 /* Load the library */
janet_lib_parse(JanetTable * env)1290 void janet_lib_parse(JanetTable *env) {
1291     JanetRegExt parse_cfuns[] = {
1292         JANET_CORE_REG("parser/new", cfun_parse_parser),
1293         JANET_CORE_REG("parser/clone", cfun_parse_clone),
1294         JANET_CORE_REG("parser/has-more", cfun_parse_has_more),
1295         JANET_CORE_REG("parser/produce", cfun_parse_produce),
1296         JANET_CORE_REG("parser/consume", cfun_parse_consume),
1297         JANET_CORE_REG("parser/byte", cfun_parse_byte),
1298         JANET_CORE_REG("parser/error", cfun_parse_error),
1299         JANET_CORE_REG("parser/status", cfun_parse_status),
1300         JANET_CORE_REG("parser/flush", cfun_parse_flush),
1301         JANET_CORE_REG("parser/state", cfun_parse_state),
1302         JANET_CORE_REG("parser/where", cfun_parse_where),
1303         JANET_CORE_REG("parser/eof", cfun_parse_eof),
1304         JANET_CORE_REG("parser/insert", cfun_parse_insert),
1305         JANET_REG_END
1306     };
1307     janet_core_cfuns_ext(env, NULL, parse_cfuns);
1308 }
1309