txlyre 4 hours ago
parent
commit
d8994c4a8a
1 changed files with 236 additions and 64 deletions
  1. 236 64
      qic.c

+ 236 - 64
qic.c

@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <math.h>
 
 #if defined(_WIN32) || defined(_WIN64)
 #define ON_WINDOWS
@@ -5130,6 +5131,14 @@ node_t *mexpr_negate(node_t *a)
 
 node_t *mexpr_add(node_t *a, node_t *b)
 {
+  if (IS_STRING(a) && IS_STRING(b)) {
+    char *buf = malloc(strlen(a->t->text) + strlen(b->t->text) + 1);
+    strcpy(buf, a->t->text);
+    strcat(buf, b->t->text);
+
+    return nodet(N_LITERAL, token(T_STRING, buf));
+  }
+
   if (!IS_NUMBER(a))
     return NULL;
 
@@ -5161,6 +5170,17 @@ node_t *mexpr_mul(node_t *a, node_t *b)
   return make_number(TO_DOUBLE(a) * TO_DOUBLE(b));
 }
 
+node_t *mexpr_pow(node_t *a, node_t *b)
+{
+  if (!IS_NUMBER(a))
+    return NULL;
+
+  if (!IS_NUMBER(b))
+    return NULL;
+
+  return make_number(pow(TO_DOUBLE(a), TO_DOUBLE(b)));
+}
+
 node_t *mexpr_div(node_t *a, node_t *b)
 {
   if (!IS_NUMBER(a))
@@ -5176,6 +5196,21 @@ node_t *mexpr_div(node_t *a, node_t *b)
   return make_number(TO_DOUBLE(a) * x);
 }
 
+node_t *mexpr_mod(node_t *a, node_t *b)
+{
+  if (!IS_NUMBER(a))
+    return NULL;
+
+  if (!IS_NUMBER(b))
+    return NULL;
+
+  double x = TO_DOUBLE(b);
+  if (x == 0)
+    return make_number(0);
+
+  return make_number(fmod(TO_DOUBLE(a), x));
+}
+
 int mexpr_equals(node_t *a, node_t *b)
 {
   if (!a && !b)
@@ -5226,136 +5261,244 @@ macro_t *find_macro(char *name, size_t argc, int *res);
 node_t *run_macro(macro_t *macro, list_t *args);
 node_t *expand_mvars(node_t *node, node_t *_node, int expr);
 
-node_t *mexpr_eval(node_t *n)
+int mdepth = 0;
+size_t macro_rlimit = 100;
+
+node_t *mexpr_eval(node_t *node)
 {
-  if (n)
-    switch (n->tag)
+  if (mdepth >= macro_rlimit) {
+    COMPILE_ERROR("max. recursion depth (%d) reached while evaluating constant expression", macro_rlimit);
+  }
+
+  mdepth++;
+
+  if (node)
+    switch (node->tag)
     {
     case N_LITERAL:
-      if (n->t->tag == T_NAME)
+      if (node->t->tag == T_NAME)
       {
-        node_t *v = const_get(n->t->text);
+        node_t *v = const_get(node->t->text);
         if (v)
-          return mexpr_eval(v);
+          node = mexpr_eval(v);
       }
       break;
 
     case N_UNARY_PLUS:
-      return mexpr_eval(n->a);
+      node = mexpr_eval(node->a);
       break;
+
     case N_NEGATE:
     {
-      node_t *a = mexpr_eval(n->a);
+      node_t *a = mexpr_eval(node->a);
 
-      return mexpr_negate(a);
-    }
+      node = mexpr_negate(a);
+    } break;
+
+    case N_EQUALS:
+    {
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
+
+      node = mexpr_equals(a, b)? nodet(N_LITERAL, token(T_TRUE, "true")): nodet(N_LITERAL, token(T_FALSE, "false"));
+    } break;
+
+    case N_NOTEQUALS:
+    {
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
+
+      node = !mexpr_equals(a, b)? nodet(N_LITERAL, token(T_TRUE, "true")): nodet(N_LITERAL, token(T_FALSE, "false"));
+    } break;
 
     case N_ADD:
     {
-      node_t *a = mexpr_eval(n->a);
-      node_t *b = mexpr_eval(n->b);
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
 
-      if (!IS_NUMBER(a) && IS_NUMBER(b))
-        return node2(N_ADD, n->a, b);
+      if (IS_STRING(a) && IS_STRING(b)) {
+        node = mexpr_add(a, b);
 
-      if (IS_NUMBER(a) && !IS_NUMBER(b))
-        return node2(N_ADD, a, n->b);
+        break;
+      }
 
-      return mexpr_add(a, b);
-    }
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_ADD, node->a, b);
+
+        break;
+      }
+
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_ADD, a, node->b);
+
+        break;
+      }
+
+      node = mexpr_add(a, b);
+    } break;
 
     case N_SUB:
     {
-      node_t *a = mexpr_eval(n->a);
-      node_t *b = mexpr_eval(n->b);
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
+
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_SUB, node->a, b);
+
+        break;
+      }
 
-      if (!IS_NUMBER(a) && IS_NUMBER(b))
-        return node2(N_SUB, n->a, b);
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_SUB, a, node->b);
 
-      if (IS_NUMBER(a) && !IS_NUMBER(b))
-        return node2(N_SUB, a, n->b);
+        break;
+      }
 
-      return mexpr_sub(a, b);
-    }
+      node = mexpr_sub(a, b);
+    } break;
 
     case N_MUL:
     {
-      node_t *a = mexpr_eval(n->a);
-      node_t *b = mexpr_eval(n->b);
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
 
-      if (!IS_NUMBER(a) && IS_NUMBER(b))
-        return node2(N_MUL, n->a, b);
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_MUL, node->a, b);
 
-      if (IS_NUMBER(a) && !IS_NUMBER(b))
-        return node2(N_MUL, a, n->b);
+        break;
+      }
 
-      return mexpr_mul(a, b);
-    }
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_MUL, a, node->b);
+
+        break;
+      }
+
+      node = mexpr_mul(a, b);
+    } break;
+
+    case N_POW:
+    {
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
+
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_POW, node->a, b);
+
+        break;
+      }
+
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_POW, a, node->b);
+
+        break;
+      }
+
+      node = mexpr_pow(a, b);
+    } break;
 
     case N_DIV:
     {
-      node_t *a = mexpr_eval(n->a);
-      node_t *b = mexpr_eval(n->b);
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
 
-      if (!IS_NUMBER(a) && IS_NUMBER(b))
-        return node2(N_DIV, n->a, b);
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_DIV, node->a, b);
 
-      if (IS_NUMBER(a) && !IS_NUMBER(b))
-        return node2(N_DIV, a, n->b);
+        break;
+      }
 
-      return mexpr_div(a, b);
-    }
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_DIV, a, node->b);
+
+        break;
+      }
+
+      node = mexpr_div(a, b);
+    } break;
+
+    case N_MOD:
+    {
+      node_t *a = mexpr_eval(node->a);
+      node_t *b = mexpr_eval(node->b);
+
+      if (!IS_NUMBER(a) && IS_NUMBER(b)) {
+        node = node2(N_MOD, node->a, b);
+
+        break;
+      }
+
+      if (IS_NUMBER(a) && !IS_NUMBER(b)) {
+        node = node2(N_MOD, a, node->b);
+
+        break;
+      }
+
+      node = mexpr_mod(a, b);
+    } break;
 
     case N_IFEXPR:
     {
-      node_t *a = mexpr_eval(n->a);
+      node_t *a = mexpr_eval(node->a);
 
       if (a)
-        return mexpr_eval(n->b);
-
-      return mexpr_eval(n->c);
-    }
+        node = mexpr_eval(node->b);
+      else
+        node = mexpr_eval(node->c);
+    } break;
 
     case N_TUPLE:
     case N_LIST:
     {
+      int f = 0;
       list_t *l = list_new();
 
-      for (size_t i = 0; i < n->l->length; i++)
+      for (size_t i = 0; i < node->l->length; i++)
       {
-        node_t *a = mexpr_eval(n->l->data[i]);
+        node_t *a = mexpr_eval(node->l->data[i]);
 
-        if (!IS_EXPR(a))
-          return NULL;
+        if (!IS_EXPR(a)) {
+          f = 1; break;
+        }
 
         list_push(l, a);
       }
 
-      return nodel(n->tag, l);
-    }
+      if (f) break;
+
+      node = nodel(node->tag, l);
+    } break;
 
     case N_COMMA:
-      return mexpr_eval(list_index(n->l, -1));
+      node = mexpr_eval(list_index(node->l, -1));
+      break;
 
     case N_MACRO_CALL:
     {
       list_t *args = list_new();
 
-      for (size_t i = 0; i < n->l->length; i++)
-        list_push(args, mexpr_eval(n->l->data[i]));
+      for (size_t i = 0; i < node->l->length; i++)
+        list_push(args, mexpr_eval(node->l->data[i]));
 
-      macro_t *m = find_macro(n->t->text, args->length, NULL);
-      if (!m)
-        return n;
+      macro_t *m = find_macro(node->t->text, args->length, NULL);
+      if (m) {
+        list_push(MVARS, table_new());
 
-      return mexpr_eval(expand_mvars(n, run_macro(m, args), 1));
-    }
+        node_t *r = run_macro(m, args);
+
+        list_pop(MVARS);
+
+        node = mexpr_eval(expand_mvars(node, r, 1));
+      }
+    } break;
 
     default:
       break;
     }
 
-  return n;
+  mdepth--;
+
+  return node;
 }
 
 node_t *mf_isExpr(list_t *t)
@@ -5614,7 +5757,13 @@ node_t *run_mexpr(node_t *node)
       if (!m)
         return NULL;
 
-      return run_macro(m, args);
+      list_push(MVARS, table_new());
+
+      node_t *r = run_macro(m, args);
+
+      list_pop(MVARS);
+
+      return r;
     }
 
     for (size_t i = 0; METAFUNCS[i].name; i++)
@@ -5662,6 +5811,14 @@ node_t *run_mexpr(node_t *node)
     return mexpr_mul(a, b);
   }
 
+  case N_POW:
+  {
+    node_t *a = run_mexpr(node->a);
+    node_t *b = run_mexpr(node->b);
+
+    return mexpr_pow(a, b);
+  }
+
   case N_DIV:
   {
     node_t *a = run_mexpr(node->a);
@@ -5670,6 +5827,14 @@ node_t *run_mexpr(node_t *node)
     return mexpr_div(a, b);
   }
 
+  case N_MOD:
+  {
+    node_t *a = run_mexpr(node->a);
+    node_t *b = run_mexpr(node->b);
+
+    return mexpr_mod(a, b);
+  }
+
   case N_EQUALS:
   {
     node_t *a = run_mexpr(node->a);
@@ -5678,6 +5843,14 @@ node_t *run_mexpr(node_t *node)
     return mexpr_equals(a, b) ? YES : NULL;
   }
 
+  case N_NOTEQUALS:
+  {
+    node_t *a = run_mexpr(node->a);
+    node_t *b = run_mexpr(node->b);
+
+    return !mexpr_equals(a, b) ? YES : NULL;
+  }
+
   case N_LT:
   {
     node_t *a = run_mexpr(node->a);
@@ -5797,7 +5970,6 @@ node_t *run_mnode(node_t *node)
 
 list_t *macro_stk;
 size_t expand_depth = 0;
-size_t macro_rlimit = 100;
 
 node_t *run_macro(macro_t *macro, list_t *args)
 {