Line data Source code
1 : // Copyright 2014 Bobby Powers. All rights reserved.
2 : // Use of this source code is governed by a BSD-style
3 : // license that can be found in the LICENSE file.
4 :
5 : #include <stdarg.h>
6 : #include <stdbool.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 :
10 : #include "utf.h"
11 : #include "sd.h"
12 : #include "sd_internal.h"
13 :
14 : // FIXME: cleanup
15 : #define MAX_ERR_LEN 64
16 :
17 : typedef struct {
18 : Lexer l;
19 : Slice errs;
20 : } Parser;
21 :
22 : static Rune nextrune(Lexer *l);
23 : static void skip_whitespace(Lexer *l);
24 : static bool numstart(Rune r);
25 : static bool identstart(Rune r);
26 : static int lex_number(Lexer *l, Token *t);
27 : static int lex_ident(Lexer *l, Token *t);
28 :
29 : static const char *const RESERVED[] = {
30 : "if",
31 : "then",
32 : "else",
33 : };
34 :
35 : static const char *const OP_WORDS[] = {
36 : "not",
37 : "and",
38 : "or",
39 : "mod",
40 : };
41 :
42 : static const char *const OP_SHORT[] = {
43 : "!",
44 : "&",
45 : "|",
46 : "%",
47 : };
48 :
49 : static const char *const UNARY = "+-!";
50 :
51 : static const char *const BINARY[] = {
52 : "^",
53 : "!", // FIXME(bp) right-associativity
54 : "*/%",
55 : "+-",
56 : "><≥≤",
57 : "=≠",
58 : "&",
59 : "|",
60 : };
61 : static const int MAX_BINARY = sizeof(BINARY)/sizeof(BINARY[0]);
62 :
63 : static void parser_errorf(Parser *p, const char *s, ...);
64 : static bool consume_tok(Parser *p, Rune r);
65 : static bool consume_any(Parser *p, const char *ops, Rune *op);
66 : static bool consume_reserved(Parser *p, const char *s);
67 : static bool expr(Parser *p, Node **n, int level);
68 : static bool fact(Parser *p, Node **n);
69 : static bool call(Parser *p, Node **n, Node *fn);
70 : static bool ident(Parser *p, Node **n);
71 : static bool num(Parser *p, Node **n);
72 :
73 : static bool visit(Walker *w, Node *n);
74 :
75 : int
76 116 : avar_eqn_parse(AVar *v)
77 : {
78 : Parser p;
79 116 : Node *n = NULL;
80 116 : int err = SD_ERR_NO_ERROR;
81 : bool ok;
82 :
83 116 : if (!v || !v->v || !v->v->eqn)
84 3 : return SD_ERR_UNSPECIFIED;
85 :
86 113 : memset(&p, 0, sizeof(p));
87 :
88 113 : lexer_init(&p.l, v->v->eqn);
89 :
90 113 : ok = expr(&p, &n, 0);
91 113 : if (!ok) {
92 : //printf("expr '%s' bad (%zu)\n", v->v->eqn, p.errs.len);
93 : //if (p.errs.len)
94 : // printf("err: %s\n", (char *)p.errs.elems[0]);
95 10 : err = SD_ERR_UNSPECIFIED;
96 10 : node_free(n);
97 10 : goto out;
98 : }
99 :
100 103 : v->node = n;
101 :
102 : // TODO(bp) check that entire token stream was consumed
103 : out:
104 117 : for (size_t i = 0; i < p.errs.len; i++)
105 4 : free(p.errs.elems[i]);
106 113 : free(p.errs.elems);
107 113 : lexer_free(&p.l);
108 113 : return err;
109 : }
110 :
111 :
112 :
113 : int
114 149 : lexer_init(Lexer *l, const char *src)
115 : {
116 149 : if (!l || !src)
117 3 : return SD_ERR_UNSPECIFIED;
118 :
119 146 : memset(l, 0, sizeof(*l));
120 146 : l->orig = src;
121 146 : l->src = strdup(src);
122 146 : int err = utf8_tolower(&l->src);
123 146 : if (err)
124 0 : return err;
125 146 : l->len = strlen(l->src);
126 146 : if (l->len)
127 144 : charntorune(&l->peek, src, l->len);
128 :
129 146 : return 0;
130 : }
131 :
132 : void
133 146 : lexer_free(Lexer *l)
134 : {
135 146 : if (!l)
136 0 : return;
137 :
138 146 : if (l->havetpeek)
139 2 : token_free(&l->tpeek);
140 146 : free(l->src);
141 146 : l->src = NULL;
142 : }
143 :
144 : void
145 5937 : token_init(Token *t)
146 : {
147 5937 : memset(t, 0, sizeof(*t));
148 5937 : }
149 :
150 : void
151 6683 : token_free(Token *t)
152 : {
153 6683 : if (!t)
154 0 : return;
155 :
156 6683 : if (t->start != t->buf) {
157 2761 : free(t->start);
158 2761 : t->start = NULL;
159 : }
160 : }
161 :
162 : int
163 5908 : lexer_peek(Lexer *l, Token *t)
164 : {
165 5908 : int err = SD_ERR_NO_ERROR;
166 :
167 5908 : if (!l || !t)
168 1 : return SD_ERR_UNSPECIFIED;
169 :
170 5907 : if (!l->havetpeek) {
171 2077 : err = lexer_nexttok(l, &l->tpeek);
172 2077 : l->havetpeek = err == SD_ERR_NO_ERROR;
173 : }
174 :
175 5907 : if (l->havetpeek) {
176 4161 : memcpy(t, &l->tpeek, sizeof(*t));
177 : // fixup pointer
178 4161 : if (l->tpeek.start == l->tpeek.buf)
179 3552 : t->start = t->buf;
180 : else
181 609 : t->start = strdup(l->tpeek.start);
182 : }
183 5907 : return err;
184 : }
185 :
186 : int
187 2532 : lexer_nexttok(Lexer *l, Token *t)
188 : {
189 : int len;
190 : int pos;
191 :
192 2532 : if (!l)
193 1 : return SD_ERR_UNSPECIFIED;
194 :
195 2531 : if (l->havetpeek) {
196 329 : if (!t)
197 0 : return SD_ERR_UNSPECIFIED;
198 329 : token_free(t);
199 :
200 329 : memcpy(t, &l->tpeek, sizeof(*t));
201 : // fixup pointer
202 329 : if (l->tpeek.start == l->tpeek.buf)
203 283 : t->start = t->buf;
204 329 : l->havetpeek = false;
205 : // if we're consuming the peeked token, we are
206 : // transferring ownership of the malloc'd start
207 : // string, so set start to NULL here to make sure we
208 : // don't try to double free it at some point in the
209 : // future.
210 329 : l->tpeek.start = NULL;
211 329 : return SD_ERR_NO_ERROR;
212 : }
213 :
214 2202 : skip_whitespace(l);
215 2202 : if (!l->peek)
216 1778 : return SD_ERR_EOF;
217 :
218 424 : if (!t)
219 1 : return SD_ERR_UNSPECIFIED;
220 423 : token_free(t);
221 :
222 423 : if (numstart(l->peek))
223 130 : return lex_number(l, t);
224 293 : if (identstart(l->peek))
225 179 : return lex_ident(l, t);
226 :
227 114 : pos = l->pos;
228 :
229 : // we either have a 1 or two rune token - handle all the two
230 : // rune cases first.
231 114 : len = runelen(l->peek);
232 114 : if (l->peek == '=') {
233 7 : nextrune(l);
234 7 : if (l->peek == '=') {
235 : // eat the second '=' since we matched
236 1 : nextrune(l);
237 1 : len++;
238 : }
239 107 : } else if (l->peek == '<') {
240 8 : nextrune(l);
241 8 : if (l->peek == '=' || l->peek == '>') {
242 : // eat the second '=' since we matched
243 5 : nextrune(l);
244 5 : len++;
245 : }
246 99 : } else if (l->peek == '>') {
247 9 : nextrune(l);
248 9 : if (l->peek == '=') {
249 : // eat the second '=' since we matched
250 4 : nextrune(l);
251 4 : len++;
252 : }
253 : } else {
254 90 : nextrune(l);
255 : }
256 :
257 114 : strncpy(t->buf, &l->src[pos], len);
258 114 : t->buf[len] = '\0';
259 :
260 : // replace common multi-rune ops with single-rune equivalents.
261 114 : if (strcmp(t->buf, ">=") == 0) {
262 4 : strcpy(t->buf, "≥");
263 110 : } else if (strcmp(t->buf, "<=") == 0) {
264 2 : strcpy(t->buf, "≤");
265 108 : } else if (strcmp(t->buf, "<>") == 0) {
266 3 : strcpy(t->buf, "≠");
267 : }
268 :
269 114 : t->start = t->buf;
270 114 : t->len = strlen(t->buf);
271 114 : t->loc.line = l->line;
272 114 : t->loc.pos = pos - l->lstart;
273 114 : t->type = TOK_TOKEN;
274 114 : return 0;
275 : }
276 :
277 : Rune
278 1858 : nextrune(Lexer *l)
279 : {
280 1858 : if (l->pos < l->len) {
281 1858 : l->pos += runelen(l->peek);
282 1858 : int n = charntorune(&l->peek, &l->src[l->pos], l->len - l->pos);
283 1858 : if (!n)
284 144 : l->peek = '\0';
285 : } else {
286 0 : l->peek = '\0';
287 : }
288 :
289 1858 : return l->peek;
290 : }
291 :
292 : void
293 2202 : skip_whitespace(Lexer *l)
294 : {
295 2202 : bool in_comment = false;
296 : do {
297 2474 : if (l->peek == '\n') {
298 5 : l->line++;
299 5 : l->lstart = l->pos + 1;
300 : }
301 2474 : if (in_comment) {
302 86 : if (l->peek == '}')
303 4 : in_comment = false;
304 86 : continue;
305 : }
306 2388 : if (l->peek == '{') {
307 5 : in_comment = true;
308 5 : continue;
309 : }
310 2383 : if (!isspacerune(l->peek))
311 2195 : break;
312 279 : } while (nextrune(l));
313 2202 : }
314 :
315 : bool
316 716 : numstart(Rune r)
317 : {
318 716 : return (r >= '0' && r <= '9') || r == '.';
319 : }
320 :
321 : bool
322 293 : identstart(Rune r)
323 : {
324 293 : return !numstart(r) && (isalpharune(r) || r == '_' || r == '"');
325 : }
326 :
327 : int
328 130 : lex_number(Lexer *l, Token *t)
329 : {
330 : Rune r;
331 130 : int pos = l->pos;
332 130 : bool have_e = false;
333 130 : bool have_dot1 = false;
334 130 : bool have_dot2 = false;
335 :
336 : // approximately match /\d*(\.\d*)?(e(\d+(\.\d*)?)?)?/
337 390 : while ((r = nextrune(l))) {
338 186 : if (r >= '0' && r <= '9')
339 105 : continue;
340 81 : if (r == '.') {
341 18 : if (!have_e && !have_dot1) {
342 13 : have_dot1 = true;
343 13 : continue;
344 5 : } else if (have_e && !have_dot2) {
345 3 : have_dot2 = true;
346 3 : continue;
347 : }
348 2 : break;
349 : }
350 63 : if (r == 'e') {
351 10 : if (!have_e) {
352 9 : have_e = true;
353 9 : continue;
354 : }
355 1 : break;
356 : }
357 : // non-error end of number
358 53 : break;
359 : }
360 :
361 130 : t->len = l->pos - pos;
362 130 : if (t->len < TOKBUF_LEN) {
363 128 : t->start = t->buf;
364 : } else {
365 2 : t->start = malloc(t->len + 1);
366 2 : if (!t->start)
367 0 : return SD_ERR_NOMEM;
368 : }
369 130 : memcpy(t->start, &l->src[pos], t->len);
370 130 : t->start[t->len] = '\0';
371 :
372 130 : t->loc.line = l->line;
373 130 : t->loc.pos = pos - l->lstart;
374 130 : t->type = TOK_NUMBER;
375 130 : return 0;
376 : }
377 :
378 : int
379 179 : lex_ident(Lexer *l, Token *t)
380 : {
381 : Rune r;
382 179 : bool quoted = l->peek == '"';
383 179 : int pos = l->pos;
384 :
385 : // Eat opening "
386 179 : if (quoted)
387 5 : nextrune(l);
388 :
389 1364 : while ((r = nextrune(l))) {
390 1136 : if (isalpharune(r))
391 923 : continue;
392 213 : if (r == '_')
393 75 : continue;
394 138 : if (r >= '0' && r <= '9')
395 4 : continue;
396 134 : if (quoted) {
397 9 : if (r == '"') {
398 : // Eat closing "
399 5 : nextrune(l);
400 5 : break;
401 : }
402 4 : if (isspacerune(r))
403 4 : continue;
404 : // TODO: check for escape sequences
405 : }
406 125 : break;
407 : }
408 :
409 179 : t->len = l->pos - pos;
410 179 : if (t->len < TOKBUF_LEN) {
411 129 : t->start = t->buf;
412 : } else {
413 50 : t->start = malloc(t->len + 1);
414 50 : if (!t->start)
415 0 : return SD_ERR_NOMEM;
416 : }
417 179 : memcpy(t->start, &l->src[pos], t->len);
418 179 : t->start[t->len] = '\0';
419 :
420 179 : t->loc.line = l->line;
421 179 : t->loc.pos = pos - l->lstart;
422 179 : t->type = TOK_IDENT;
423 :
424 616 : for (size_t i = 0; i < sizeof(RESERVED)/sizeof(*RESERVED); i++) {
425 485 : if (strcmp(t->start, RESERVED[i]) == 0) {
426 48 : t->type = TOK_RESERVED;
427 48 : break;
428 : }
429 : }
430 :
431 877 : for (size_t i = 0; i < sizeof(OP_WORDS)/sizeof(*OP_WORDS); i++) {
432 704 : if (strcmp(t->start, OP_WORDS[i]) == 0) {
433 6 : strcpy(t->buf, OP_SHORT[i]);
434 6 : t->start = t->buf;
435 6 : t->len = strlen(t->buf);
436 6 : t->type = TOK_TOKEN;
437 6 : break;
438 : }
439 : }
440 :
441 179 : return 0;
442 : }
443 :
444 : bool
445 1588 : expr(Parser *p, Node **n, int level)
446 : {
447 : Token t;
448 : int err;
449 1588 : Node *x = NULL;
450 1588 : Node *lhs = NULL;
451 1588 : Node *rhs = NULL;
452 1588 : bool ok = false;
453 : const char *ops;
454 : Rune op;
455 :
456 1588 : token_init(&t);
457 :
458 1588 : err = lexer_peek(&p->l, &t);
459 1588 : if (err == SD_ERR_EOF)
460 8 : return true;
461 :
462 1580 : if (level + 1 == MAX_BINARY)
463 223 : ok = fact(p, &lhs);
464 : else
465 1357 : ok = expr(p, &lhs, level + 1);
466 :
467 1580 : if (!ok)
468 103 : goto out;
469 :
470 1477 : ops = BINARY[level];
471 : while (true) {
472 1530 : ok = consume_any(p, ops, &op);
473 : // its fine if we didn't have a binary operator
474 1530 : if (!ok) {
475 1473 : ok = true;
476 1473 : break;
477 : }
478 :
479 : // expr must be passed level + 1, not 0, to preserve
480 : // left-associativity
481 57 : if (level + 1 == MAX_BINARY)
482 1 : ok = fact(p, &rhs);
483 : else
484 56 : ok = expr(p, &rhs, level + 1);
485 57 : if (!ok || !rhs) {
486 4 : ok = false;
487 4 : goto out;
488 : }
489 :
490 53 : x = node(N_BINARY);
491 : // FIXME(bp) no mem
492 53 : if (!x) {
493 0 : ok = false;
494 0 : goto out;
495 : }
496 53 : x->left = lhs;
497 53 : x->right = rhs;
498 53 : x->op = op;
499 53 : lhs = x;
500 53 : x = NULL;
501 53 : rhs = NULL;
502 53 : }
503 1473 : *n = lhs;
504 1473 : lhs = NULL;
505 : out:
506 1580 : node_free(lhs);
507 1580 : node_free(rhs);
508 1580 : token_free(&t);
509 1580 : return ok;
510 : }
511 :
512 : bool
513 224 : fact(Parser *p, Node **n)
514 : {
515 : Node *x, *l, *r, *cond;
516 : Rune op;
517 224 : bool ok = false;
518 :
519 224 : x = l = r = cond = NULL;
520 :
521 224 : if (consume_tok(p, '(')) {
522 7 : ok = expr(p, &l, 0);
523 7 : if (!ok)
524 2 : goto out;
525 5 : if (!consume_tok(p, ')')) {
526 1 : parser_errorf(p, "expected ')'");
527 1 : ok = false;
528 1 : goto out;
529 : }
530 4 : x = node(N_PAREN);
531 : // FIXME(bp) no mem
532 4 : if (!x) {
533 0 : ok = false;
534 0 : goto out;
535 : }
536 4 : x->left = l;
537 4 : *n = x;
538 4 : x = NULL;
539 4 : l = NULL;
540 4 : ok = true;
541 4 : goto out;
542 : }
543 :
544 217 : if (consume_any(p, UNARY, &op)) {
545 3 : ok = expr(p, &l, 0);
546 3 : if (!ok)
547 0 : goto out;
548 :
549 3 : x = node(N_UNARY);
550 3 : if (!x) {
551 0 : ok = false;
552 0 : goto out;
553 : }
554 :
555 3 : x->op = op;
556 3 : x->left = l;
557 3 : *n = x;
558 3 : x = NULL;
559 3 : l = NULL;
560 3 : ok = true;
561 3 : goto out;
562 : }
563 :
564 214 : if ((ok = num(p, n)))
565 94 : goto out;
566 120 : if (consume_reserved(p, "if")) {
567 14 : ok = expr(p, &cond, 0);
568 14 : if (!ok)
569 2 : goto out;
570 12 : if (!consume_reserved(p, "then")) {
571 1 : parser_errorf(p, "expected 'then'");
572 1 : ok = false;
573 1 : goto out;
574 : }
575 11 : ok = expr(p, &l, 0);
576 11 : if (!ok || !l) {
577 1 : ok = false;
578 1 : goto out;
579 : }
580 10 : if (consume_reserved(p, "else")) {
581 10 : ok = expr(p, &r, 0);
582 10 : if (!ok || !r) {
583 1 : ok = false;
584 1 : goto out;
585 : }
586 : }
587 :
588 9 : x = node(N_IF);
589 9 : if (!x) {
590 0 : ok = false;
591 0 : goto out;
592 : }
593 9 : x->cond = cond;
594 9 : x->left = l;
595 9 : x->right = r;
596 9 : *n = x;
597 9 : cond = l = r = x = NULL;
598 9 : goto out;
599 : }
600 106 : if ((ok = ident(p, &x))) {
601 104 : if (consume_tok(p, '(')) {
602 8 : ok = call(p, n, x);
603 8 : x = NULL;
604 : } else {
605 96 : *n = x;
606 96 : x = NULL;
607 : }
608 104 : goto out;
609 : }
610 : // TODO(bp) []
611 : out:
612 224 : node_free(x);
613 224 : node_free(l);
614 224 : node_free(r);
615 224 : node_free(cond);
616 224 : return ok;
617 : }
618 :
619 : bool
620 8 : call(Parser *p, Node **n, Node *fn)
621 : {
622 8 : Node *arg = NULL;
623 8 : Node *x = node(N_CALL);
624 :
625 : // FIXME: no mem
626 8 : if (!x)
627 0 : goto error;
628 8 : x->left = fn;
629 8 : fn = NULL;
630 :
631 : // no-arg call - simplifies logic to special case this.
632 8 : if (consume_tok(p, ')'))
633 1 : goto out;
634 :
635 : while (true) {
636 17 : bool ok = expr(p, &arg, 0);
637 17 : if (!ok) {
638 1 : parser_errorf(p, "call: expected expr arg");
639 1 : goto error;
640 : }
641 16 : slice_append(&x->args, arg);
642 16 : arg = NULL;
643 16 : if (consume_tok(p, ','))
644 10 : continue;
645 6 : if (consume_tok(p, ')'))
646 5 : break;
647 1 : parser_errorf(p, "call: expected ',' or ')'");
648 1 : goto error;
649 10 : }
650 : out:
651 6 : *n = x;
652 6 : return true;
653 : error:
654 2 : node_free(arg);
655 2 : node_free(x);
656 2 : node_free(fn);
657 2 : return false;
658 : }
659 :
660 : bool
661 106 : ident(Parser *p, Node **n)
662 : {
663 : Token t;
664 : Node *x;
665 : int err;
666 106 : bool ok = false;
667 :
668 106 : token_init(&t);
669 :
670 106 : err = lexer_peek(&p->l, &t);
671 : // FIXME(bp) log
672 106 : if (err || t.type != TOK_IDENT)
673 : goto error;
674 :
675 104 : lexer_nexttok(&p->l, &t);
676 :
677 104 : x = node(N_IDENT);
678 : // FIXME(bp) no mem
679 104 : if (!x)
680 0 : goto error;
681 104 : x->sval = normalize_name(t.start);
682 104 : *n = x;
683 104 : ok = true;
684 : error:
685 106 : token_free(&t);
686 106 : return ok;
687 : }
688 :
689 : bool
690 214 : num(Parser *p, Node **n)
691 : {
692 : Token t;
693 : Node *x;
694 : int err;
695 214 : bool ok = false;
696 :
697 214 : token_init(&t);
698 214 : err = lexer_peek(&p->l, &t);
699 214 : if (err || t.type != TOK_NUMBER)
700 : goto error;
701 :
702 94 : lexer_nexttok(&p->l, &t);
703 94 : x = node(N_FLOATLIT);
704 : // FIXME(bp) no mem
705 94 : if (!x)
706 0 : goto error;
707 :
708 94 : x->sval = strdup(t.start);
709 94 : *n = x;
710 94 : ok = true;
711 : error:
712 214 : token_free(&t);
713 214 : return ok;
714 : }
715 :
716 : bool
717 142 : consume_reserved(Parser *p, const char *s)
718 : {
719 : Token t;
720 : int err;
721 142 : bool ok = false;
722 :
723 142 : token_init(&t);
724 :
725 142 : err = lexer_peek(&p->l, &t);
726 142 : if (err)
727 1 : goto out;
728 : // FIXME(bp) better error handling
729 141 : ok = t.type == TOK_RESERVED && strcmp(t.start, s) == 0;
730 141 : if (ok)
731 35 : lexer_nexttok(&p->l, &t);
732 : out:
733 142 : token_free(&t);
734 142 : return ok;
735 : }
736 :
737 : bool
738 3854 : consume_tok(Parser *p, Rune r)
739 : {
740 : Token t;
741 : Rune tr;
742 : int err;
743 3854 : bool ok = false;
744 :
745 3854 : token_init(&t);
746 :
747 3854 : err = lexer_peek(&p->l, &t);
748 3854 : if (err)
749 1736 : goto out;
750 2118 : charntorune(&tr, t.start, t.len);
751 : // FIXME(bp) better error handling
752 2118 : ok = t.type == TOK_TOKEN && tr == r;
753 2118 : if (ok)
754 95 : lexer_nexttok(&p->l, &t);
755 : out:
756 3854 : token_free(&t);
757 3854 : return ok;
758 : }
759 :
760 : bool
761 1747 : consume_any(Parser *p, const char *ops, Rune *op)
762 : {
763 : size_t len, pos, n;
764 : Rune r;
765 : bool ok;
766 :
767 1747 : len = strlen(ops);
768 :
769 5178 : for (pos = 0; (n = charntorune(&r, &ops[pos], len-pos)); pos += n) {
770 3491 : ok = consume_tok(p, r);
771 3491 : if (ok) {
772 60 : *op = r;
773 60 : return true;
774 : }
775 : }
776 1687 : return false;
777 : }
778 :
779 : void
780 4 : parser_errorf(Parser *p, const char *fmt, ...)
781 : {
782 4 : char *err = calloc(MAX_ERR_LEN, 1);
783 : // FIXME: no mem
784 4 : if (!err)
785 0 : return;
786 :
787 : // FIXME: peek current token - it is where the error is located.
788 : va_list args;
789 :
790 4 : va_start(args, fmt);
791 4 : vsnprintf(err, MAX_ERR_LEN, fmt, args);
792 4 : va_end(args);
793 :
794 4 : slice_append(&p->errs, err);
795 : }
796 :
797 : Node *
798 275 : node(NodeType ty)
799 : {
800 275 : Node *n = calloc(1, sizeof(*n));
801 275 : if (!n)
802 0 : return NULL;
803 275 : n->type = ty;
804 275 : return n;
805 : }
806 :
807 : void
808 5070 : node_free(Node *n)
809 : {
810 5070 : if (!n)
811 4795 : return;
812 :
813 275 : node_free(n->left);
814 275 : node_free(n->right);
815 275 : node_free(n->cond);
816 275 : free(n->sval);
817 :
818 291 : for (size_t i = 0; i < n->args.len; i++)
819 16 : node_free((Node *)n->args.elems[i]);
820 275 : free(n->args.elems);
821 :
822 : // XXX(bp) remove?
823 275 : memset(n, 0, sizeof(*n));
824 :
825 275 : free(n);
826 : }
827 :
828 : bool
829 257 : visit(Walker *w, Node *n)
830 : {
831 257 : Walker *wc = NULL;
832 257 : bool ok = true;
833 :
834 257 : w->ops->start(w, n);
835 :
836 257 : switch (n->type) {
837 : case N_PAREN:
838 4 : wc = w->ops->start_child(w, n->left);
839 4 : ok = visit(wc, n->left);
840 4 : wc->ops->unref(wc);
841 4 : w->ops->end_child(w, n->left);
842 4 : break;
843 : case N_FLOATLIT:
844 : case N_IDENT:
845 182 : break;
846 : case N_CALL:
847 6 : wc = w->ops->start_child(w, n->left);
848 6 : if (wc) {
849 2 : ok = visit(wc, n->left);
850 2 : wc->ops->unref(wc);
851 2 : w->ops->end_child(w, n->left);
852 : }
853 6 : if (!ok)
854 0 : break;
855 19 : for (size_t i = 0; i < n->args.len; i++) {
856 13 : Node *nc = n->args.elems[i];
857 13 : wc = w->ops->start_child(w, nc);
858 13 : ok = visit(wc, nc);
859 13 : wc->ops->unref(wc);
860 13 : w->ops->end_child(w, nc);
861 13 : if (!ok)
862 0 : break;
863 : }
864 6 : break;
865 : case N_UNARY:
866 3 : wc = w->ops->start_child(w, n->left);
867 3 : ok = visit(wc, n->left);
868 3 : wc->ops->unref(wc);
869 3 : w->ops->end_child(w, n->left);
870 3 : if (!ok)
871 0 : break;
872 3 : break;
873 : case N_IF:
874 9 : wc = w->ops->start_child(w, n->cond);
875 9 : ok = visit(wc, n->cond);
876 9 : wc->ops->unref(wc);
877 9 : w->ops->end_child(w, n->cond);
878 9 : if (!ok)
879 0 : break;
880 : // fallthrough
881 : case N_BINARY:
882 62 : wc = w->ops->start_child(w, n->left);
883 62 : ok = visit(wc, n->left);
884 62 : wc->ops->unref(wc);
885 62 : w->ops->end_child(w, n->left);
886 62 : if (!ok)
887 0 : break;
888 62 : wc = w->ops->start_child(w, n->right);
889 62 : ok = visit(wc, n->right);
890 62 : wc->ops->unref(wc);
891 62 : w->ops->end_child(w, n->right);
892 62 : if (!ok)
893 0 : break;
894 62 : break;
895 : case N_UNKNOWN:
896 : default:
897 : // TODO: error
898 0 : ok = false;
899 0 : break;
900 : }
901 :
902 257 : if (w->ops->end)
903 0 : w->ops->end(w);
904 :
905 257 : return ok;
906 : }
907 :
908 : bool
909 103 : node_walk(Walker *w, Node *n)
910 : {
911 : bool ok;
912 :
913 103 : if (!w || !n)
914 1 : return false;
915 :
916 : // XXX: not necessary prob
917 102 : w->ops->ref(w);
918 :
919 102 : ok = visit(w, n);
920 :
921 102 : w->ops->unref(w);
922 :
923 102 : return ok;
924 : }
|