LCOV - code coverage report
Current view: top level - libsd - parse.c (source / functions) Hit Total Coverage
Test: app.info Lines: 486 516 94.2 %
Date: 2015-08-29 Functions: 26 26 100.0 %

          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             : }

Generated by: LCOV version 1.10