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