txlyre 3 weeks ago
parent
commit
096633585c
1 changed files with 80 additions and 0 deletions
  1. 80 0
      qic.c

+ 80 - 0
qic.c

@@ -417,6 +417,7 @@ typedef struct {
     T_MINUSMINUS,
     T_SLASHSLASH,
     T_COLONASSIGN,
+    T_ARROW,
 
     T_PLUS,
     T_MINUS,
@@ -932,6 +933,8 @@ token_t *next_token(char *source, size_t *pos) {
     return TK(GE);
   else if (strncmp(&source[*pos], ":=", 2) == 0 && ++(*pos) && ++(*pos))
     return TK(COLONASSIGN);
+  else if (strncmp(&source[*pos], "=>", 2) == 0 && ++(*pos) && ++(*pos))
+    return TK(ARROW);
   else if (source[*pos] == '(' && ++(*pos))
     return TK(LPAR);
   else if (source[*pos] == ')' && ++(*pos))
@@ -1092,6 +1095,7 @@ struct _node_t {
 
     N_IFEXPR,
     N_FUNCEXPR,
+    N_SWITCHEXPR,
 
     N_LOGOR,
     N_LOGAND,
@@ -1780,6 +1784,42 @@ node_t *parse_postfix(list_t *tokens, size_t *pos) {
     return NODE1(INC, a);
   else if (MATCH(MINUSMINUS))
     return NODE1(DEC, a);
+  else if (MATCH(SWITCH)) {
+    EXPECT(LCB, "{");
+
+    list_t *cases = list_new();
+    node_t *default_case = NULL;
+
+    for (;;) {
+      if (MATCH(DEFAULT)) {
+        MATCH(ARROW);
+
+        default_case = parse_expr(tokens, pos);
+
+        break;
+      }
+
+      if (AT(RCB))
+        break;
+
+      node_t *expr = parse_expr(tokens, pos);
+
+      MATCH(ARROW);
+
+      list_t *pair = list_new();
+      list_push(pair, expr);
+      list_push(pair, parse_expr(tokens, pos));
+
+      list_push(cases, pair);
+    }
+
+    EXPECT(RCB, "}");
+
+    if (!cases->length && !default_case)
+      PARSE_ERROR("empty switch expression");
+
+    return NODE2l(SWITCHEXPR, a, default_case, cases);
+  }
 
   return a;
 }
@@ -6407,6 +6447,46 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
     EMIT(")");
     break;
 
+  case N_SWITCHEXPR: {
+    NEWGID();
+
+    buffer_t *tbuf = buffer_new();
+    char *varname1 = tempvar();
+    char *varname2 = tempvar();
+    char *labelname = tempvar();
+
+    buffer_fmt(tbuf, "qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
+    buffer_fmt(tbuf, "qi_value_t *%s = state->nil;\n", varname1);
+    buffer_fmt(tbuf, "qi_value_t *%s = ", varname2);
+    compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->a);
+    buffer_fmt(tbuf, ";\n");
+
+    for (size_t i = 0; i < node->l->length; i++) {
+      list_t *pair = node->l->data[i];
+
+      buffer_fmt(tbuf, "if (_qi_equals(state, %s, ", varname2);
+      compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, pair->data[0]);
+      buffer_fmt(tbuf, ")) {\n");
+      buffer_fmt(tbuf, "%s = ", varname1);
+      compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, pair->data[1]);
+      buffer_fmt(tbuf, ";\n");
+      buffer_fmt(tbuf, "goto %s;\n}\n", labelname);
+    }
+
+    if (node->b) {
+      buffer_fmt(tbuf, "%s = ", varname1);
+      compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->b);
+      buffer_fmt(tbuf, ";\n");
+    }
+
+    buffer_fmt(tbuf, "%s: return %s;\n", labelname, varname1);
+    buffer_fmt(tbuf, "}\n");
+
+    buffer_appendb(gbuf, tbuf);
+
+    EMIT("__%s%d(state)", PREFIX, gid);
+    } break;
+
   case N_FUNCEXPR:
     compile_func(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node, NULL);
     break;