calc: generate calculators
authorMichael Wallner <mike@php.net>
Mon, 20 Feb 2017 13:10:33 +0000 (14:10 +0100)
committerMichael Wallner <mike@php.net>
Mon, 20 Feb 2017 13:10:33 +0000 (14:10 +0100)
23 files changed:
Makefile.frag
config.m4
scripts/_include.php [new file with mode: 0644]
scripts/gen_calc_basic.php [new file with mode: 0644]
scripts/gen_calc_bin.php [new file with mode: 0644]
scripts/gen_calc_bool.php [new file with mode: 0644]
scripts/gen_calc_cast.php [new file with mode: 0644]
scripts/gen_calc_cmp.php [new file with mode: 0644]
scripts/gen_calc_oper.php [new file with mode: 0644]
scripts/gen_cmp.php [deleted file]
scripts/gen_int.php [deleted file]
scripts/gen_oper.php [deleted file]
src/calc.c [deleted file]
src/calc.h
src/calc/basic.h [new file with mode: 0644]
src/calc/bin.h [new file with mode: 0644]
src/calc/bool.h [new file with mode: 0644]
src/calc/cast.h [new file with mode: 0644]
src/calc/cmp.h [new file with mode: 0644]
src/calc/oper.h [new file with mode: 0644]
src/token.h
src/token_oper_cmp.h [deleted file]
src/types/num_exp.c

index 91e5012..9e33c50 100644 (file)
@@ -36,9 +36,21 @@ $(PHP_PSI_SRCDIR)/src/parser.c: $(PHP_PSI_SRCDIR)/src/parser.re
        # trickery needed for relative #line directives
        cd $(PHP_PSI_SRCDIR) && $(RE2C) -o $@ $(patsubst $(PHP_PSI_SRCDIR)/%,%,$<)
 
-$(PHP_PSI_SRCDIR)/src/token.h: $(PHP_PSI_SRCDIR)/src/token_oper_cmp.h
-$(PHP_PSI_SRCDIR)/src/token_oper_cmp.h: $(PHP_PSI_SRCDIR)/scripts/gen_oper.php
+$(PHP_PSI_SRCDIR)/src/calc/basic.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_basic.php
        $(PHP_EXECUTABLE) $< >$@
+$(PHP_PSI_SRCDIR)/src/calc/bin.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_bin.php
+       $(PHP_EXECUTABLE) $< >$@
+$(PHP_PSI_SRCDIR)/src/calc/bool.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_bool.php
+       $(PHP_EXECUTABLE) $< >$@
+$(PHP_PSI_SRCDIR)/src/calc/cast.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_cast.php
+       $(PHP_EXECUTABLE) $< >$@
+$(PHP_PSI_SRCDIR)/src/calc/cmp.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_cmp.php
+       $(PHP_EXECUTABLE) $< >$@
+$(PHP_PSI_SRCDIR)/src/calc/oper.h: $(PHP_PSI_SRCDIR)/scripts/gen_calc_oper.php
+       $(PHP_EXECUTABLE) $< >$@
+
+.PHONY: psi-generated
+psi-generated: $(PHP_PSI_GENERATED)
 
 PHP_PSI_DEPEND = $(patsubst $(PHP_PSI_SRCDIR)/%,$(PHP_PSI_BUILDDIR)/%,$(PHP_PSI_SOURCES:.c=.dep))
 
@@ -47,7 +59,6 @@ $(PHP_PSI_BUILDDIR)/%.dep: $(PHP_PSI_SRCDIR)/%.c
                $(CPPFLAGS) $(DEFS) $(INCLUDES) $< \
                        || touch $@
 
-token_oper_cmp.h: $(PHP_PSI_SRCDIR)/src/token_oper_cmp.h
 php_psi_stdinc.h:
 php_psi_posix.h:
 
index 3ced949..828c937 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -151,18 +151,29 @@ if test "$PHP_PSI" != no; then
 
        PHP_ADD_INCLUDE($PHP_PSI_SRCDIR)
        PHP_ADD_INCLUDE($PHP_PSI_SRCDIR/src)
+       PHP_ADD_INCLUDE($PHP_PSI_SRCDIR/src/calc)
        PHP_ADD_INCLUDE($PHP_PSI_SRCDIR/src/types)
        PHP_ADD_INCLUDE($PHP_PSI_BUILDDIR)
        PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src)
        PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src/types)
 
-       PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && ls *.h types/*.h)`
+       PHP_PSI_HEADERS=" \
+               src/calc/basic.h src/calc/bin.h src/calc/bool.h src/calc/cast.h \
+               src/calc/cmp.h src/calc/oper.h \
+               `(cd $PHP_PSI_SRCDIR/src && ls *.h types/*.h)` \
+       "
        # parser* should come first
        PHP_PSI_SOURCES=" \
-               src/parser_proc.c src/parser.c
-               `(cd $PHP_PSI_SRCDIR && ls src/*.c src/types/*.c | $EGREP -v '^src/parser')` \
+               src/parser_proc.c src/parser.c \
+               `(cd $PHP_PSI_SRCDIR && ls src/*.c src/types/*.c \
+                       | $EGREP -v '^src/parser' \
+               )` \
+       "
+       PHP_PSI_GENERATED=" \
+               src/parser_proc.y src/parser_proc.c src/parser.c \
+               src/calc/basic.h src/calc/bin.h src/calc/bool.h src/calc/cast.h \
+               src/calc/cmp.h src/calc/oper.h \
        "
-       PHP_PSI_GENERATED="src/parser_proc.y src/parser_proc.c src/parser.c"
 
        PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared)
        PHP_INSTALL_HEADERS(ext/psi, php_psi.h $PHP_PSI_HEADERS)
diff --git a/scripts/_include.php b/scripts/_include.php
new file mode 100644 (file)
index 0000000..acd539b
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+ob_start(function($s) {
+       return preg_replace("/(?<=[^ \t])[ \t]+\$/m", "", $s);
+});
+
+$types = [
+               "INT8" => "i8",
+               "UINT8" => "u8",
+               "INT16" => "i16",
+               "UINT16" => "u16",
+               "INT32" => "i32",
+               "UINT32" => "u32",
+               "INT64" => "i64",
+               "UINT64" => "u64",
+               "FLOAT" => "fval",
+               "DOUBLE" => "dval",
+               "LONG_DOUBLE" => "ldval",
+];
+
+function t_is_int($t) {
+       switch ($t{0}) {
+               case "U":
+               case "I":
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+function t_is_special($t) {
+       switch ($t) {
+               case "LONG_DOUBLE":
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+?>
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
\ No newline at end of file
diff --git a/scripts/gen_calc_basic.php b/scripts/gen_calc_basic.php
new file mode 100644 (file)
index 0000000..0af83a8
--- /dev/null
@@ -0,0 +1,143 @@
+<?php
+
+include __DIR__."/_include.php";
+
+$ops = [
+               "add" => "+",
+               "sub" => "-",
+               "mul" => "*",
+               "div" => "/",
+];
+
+function t_for_res($t1, $t2) {
+       global $types;
+       
+       $p = array_flip(array_keys($types));
+       
+       if ($p[$t2] >= 8 || $p[$t1] >= 8) {
+               if ($p[$t2] > $p[$t1]) {
+                       return $t2;
+               }
+               return $t1;
+       }
+       
+       $u1 = $t1{0} === "U";
+       $s1 = substr($t1, $u1 ? 4 : 3);
+       $u2 = $t2{0} === "U";
+       $s2 = substr($t2, $u2 ? 4 : 3);
+       
+       if ($u1 && $u2)  {
+               return "UINT".min(64,max($s1*2,$s2*2));
+       } else {
+               return "INT".min(64,max($s1*2,$s2*2));
+       }
+       
+}
+
+function v_for_res($t1, $t2) {
+       global $types;
+       
+       return $types[t_for_res($t1, $t2)];
+}
+
+?>
+
+
+<?php foreach ($ops as $op_name => $op) : ?>
+static inline token_t psi_calc_<?=$op_name?>(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       
+       switch (t1) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               switch (t2) {<?php /*nobr*/ ?>
+               <?php foreach ($types as $t2 => $v2) : ?>
+               <?php if (t_is_special($t2)) :?>
+       
+#      if HAVE_<?=$t2?>
+               <?php endif; ?>
+               
+               case PSI_T_<?=$t2?>:
+                       res-><?=v_for_res($t1, $t2)?> = v1-><?=$v1?> <?=$op?> v2-><?=$v2?>;
+                       return PSI_T_<?=t_for_res($t1, $t2)?>;<?php /*nobr*/ ?>
+               <?php if (t_is_special($t2)) : ?>
+
+#      endif
+               <?php endif; ?>
+               <?php endforeach; ?>
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;<?php /*nobr*/ ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       return 0;
+}
+<?php endforeach; ?>
+
+
+static inline token_t psi_calc_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+       
+       switch (t1) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               i1.i64 = v1-><?=$v1?>;
+               break;
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       switch (t2) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t2 => $v2) : ?>
+       <?php if (t_is_special($t2)) :?>
+       
+#if HAVE_<?=$t2?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t2?>:
+               i2.i64 = v2-><?=$v2?>;
+               break;<?php /*nobr*/ ?>
+       <?php endforeach; ?>
+       <?php if (t_is_special($t2)) : ?>
+
+#endif
+       <?php endif; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       res->i64 = i1.i64 % i2.i64;
+       return PSI_T_INT64;
+}
diff --git a/scripts/gen_calc_bin.php b/scripts/gen_calc_bin.php
new file mode 100644 (file)
index 0000000..c7dbf01
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+
+include __DIR__."/_include.php";
+
+$ops = [
+               "lshift" => "<<",
+               "rshift" => ">>",
+               "and" => "&",
+               "xor" => "^",
+               "or" => "|",
+];
+
+?>
+
+<?php foreach ($ops as $op_name => $op) : ?>
+
+static inline token_t psi_calc_bin_<?=$op_name?>(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+       
+       switch (t1) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               i1.u64 = v1-><?=$v1?>;
+               break;
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       switch (t2) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t2 => $v2) : ?>
+       <?php if (t_is_special($t2)) :?>
+       
+#if HAVE_<?=$t2?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t2?>:
+               i2.u64 = v2-><?=$v2?>;
+               break;<?php /*nobr*/ ?>
+       <?php endforeach; ?>
+       <?php if (t_is_special($t2)) : ?>
+
+#endif
+       <?php endif; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       res->u64 = i1.u64 <?=$op?> i2.u64;
+       return PSI_T_UINT64;
+}
+<?php endforeach; ?>
+
+static inline token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1;
+
+       (void) t2;
+       (void) v2;
+       
+       switch (t1) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               i1.u64 = v1-><?=$v1?>;
+               break;
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = ~i1.u64;
+       return PSI_T_UINT64;
+}
\ No newline at end of file
diff --git a/scripts/gen_calc_bool.php b/scripts/gen_calc_bool.php
new file mode 100644 (file)
index 0000000..1aaad08
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+include __DIR__."/_include.php";
+?>
+
+
+static inline token_t psi_calc_bool_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       (void) t2;
+       (void) v2;
+       
+       switch (t1) {<?php /*nobr */ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               res->u8 = !v1-><?=$v1?>;
+               break;<?php /*nobr */ ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_bool_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {<?php /*nobr */ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               if (v1-><?=$v1?>)
+                       goto return_true;
+               break;<?php /*nobr */ ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {<?php /*nobr */ ?>
+       <?php foreach ($types as $t2 => $v2) : ?>
+       <?php if (t_is_special($t2)) :?>
+       
+#if HAVE_<?=$t2?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t2?>:
+               if (v2-><?=$v2?>)
+                       goto return_true;
+               break;<?php /*nobr */ ?>
+       <?php if (t_is_special($t2)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       res->u8 = 0;
+       return PSI_T_UINT8;
+       
+return_true:
+       res->u8 = 1;
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_bool_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {<?php /*nobr */ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) :?>
+       
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               if (!v1-><?=$v1?>)
+                       goto return_false;
+               break;<?php /*nobr */ ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {<?php /*nobr */ ?>
+       <?php foreach ($types as $t2 => $v2) : ?>
+       <?php if (t_is_special($t2)) :?>
+       
+#if HAVE_<?=$t2?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t2?>:
+               if (!v2-><?=$v2?>)
+                       goto return_false;
+               break;<?php /*nobr */ ?>
+       <?php if (t_is_special($t2)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       
+       res->u8 = 1;
+       return PSI_T_UINT8;
+       
+return_false:
+       res->u8 = 0;
+       return PSI_T_UINT8;
+}
diff --git a/scripts/gen_calc_cast.php b/scripts/gen_calc_cast.php
new file mode 100644 (file)
index 0000000..9015008
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+include __DIR__."/_include.php";
+?>
+
+
+static inline void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
+{
+       switch (out_type) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t => $v) : ?>
+       <?php if (t_is_special($t)) : ?>
+
+#if HAVE_<?=$t?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t?>:
+               switch (in_type) {<?php /*nobr*/ ?>
+               <?php foreach ($types as $t_in => $v_in) : ?>
+               <?php if (t_is_special($t_in)) :?>
+       
+#      if HAVE_<?=$t_in?>
+               <?php endif; ?>
+               
+               case PSI_T_<?=$t_in?>:
+                       out_val-><?=$v?> = in_val-><?=$v_in?>;
+                       break;<?php /*nobr*/ ?>
+               <?php if (t_is_special($t_in)) : ?>
+
+#      endif
+               <?php endif; ?>
+               <?php endforeach; ?>
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;<?php /*nobr*/ ?>
+       <?php if (t_is_special($t)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+}
+
diff --git a/scripts/gen_calc_cmp.php b/scripts/gen_calc_cmp.php
new file mode 100644 (file)
index 0000000..8f82bfb
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+include __DIR__."/_include.php";
+
+$ops = [
+               "eq" => "==",
+               "ne" => "!=",
+               "lt" => "<",
+               "gt" => ">",
+               "le" => "<=",
+               "ge" => ">="
+];
+
+?>
+
+<?php foreach ($ops as $op_name => $op) : ?>
+
+static inline token_t psi_calc_cmp_<?=$op_name?>(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {<?php /*nobr*/ ?>
+       <?php foreach ($types as $t1 => $v1) : ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#if HAVE_<?=$t1?>
+       <?php endif; ?>
+
+       case PSI_T_<?=$t1?>:
+               switch (t2) {<?php /*nobr*/ ?>
+               <?php foreach ($types as $t2 => $v2) : ?>
+               <?php if (t_is_special($t2)) :?>
+       
+#      if HAVE_<?=$t2?>
+               <?php endif; ?>
+               
+               case PSI_T_<?=$t2?>:
+                       res->u8 = v1-><?=$v1?> <?=$op?> v2-><?=$v2?>;
+                       break;<?php /*nobr*/ ?>
+               <?php if (t_is_special($t2)) : ?>
+
+#      endif
+               <?php endif; ?>
+               <?php endforeach; ?>
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;<?php /*nobr*/ ?>
+       <?php if (t_is_special($t1)) : ?>
+
+#endif
+       <?php endif; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+<?php endforeach; ?>
diff --git a/scripts/gen_calc_oper.php b/scripts/gen_calc_oper.php
new file mode 100644 (file)
index 0000000..126e9ac
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+include __DIR__."/_include.php";
+
+$oper = [
+               ["NOT", "TILDE"],
+               ["ASTERISK", "SLASH", "MODULO"],
+               ["PLUS", "MINUS"],
+               ["LSHIFT", "RSHIFT"],
+               ["LCHEVR", "CMP_LE", "RCHEVR", "CMP_GE"],
+               ["AMPERSAND"],
+               ["CMP_EQ", "CMP_NE"],
+               ["CARET"],
+               ["PIPE"],
+               ["AND"],
+               ["OR"]
+];
+
+?>
+
+
+static inline int psi_calc_oper(token_t op1, token_t op2)
+{
+       if (PSI_T_LPAREN == op2) {
+               return -1;
+       } else if (PSI_T_LPAREN == op1) {
+               return 1;
+       } else if (op1 == op2) {
+               return 0;
+       } else if (!op1) {
+               return 1;
+       } else if (!op2) {
+               return -1;
+       }
+
+       switch (op1) {<?php /*nobr*/ ?>
+       <?php foreach ($oper as $prec1 => $ops1) : ?>
+       <?php foreach ($ops1 as $op1) : ?>
+
+       case PSI_T_<?=$op1?>:
+               switch (op2) {<?php /*nobr*/ ?>
+               <?php foreach ($oper as $prec2 => $ops2) : ?>
+                       <?php foreach ($ops2 as $op2) : ?>
+
+               case PSI_T_<?=$op2?>:
+                       return <?=$prec1==$prec2?0:($prec1>$prec2?1:-1)?>;<?php /*nobr */ ?>
+                       <?php endforeach; ?>
+               <?php endforeach; ?>
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       <?php endforeach; ?>
+       <?php endforeach; ?>
+
+       default:
+               assert(0);
+               break;
+       }
+       return 0;
+}
diff --git a/scripts/gen_cmp.php b/scripts/gen_cmp.php
deleted file mode 100644 (file)
index 89524ee..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-$types = [
-               "FLOAT" => "fval", 
-               "DOUBLE" => "dval",
-               "LONG_DOUBLE" => "ldval",
-               "INT8" => "i8",
-               "UINT8" => "u8",
-               "INT16" => "i16", 
-               "UINT16" => "u16",
-               "INT32" => "i32", 
-               "UINT32" => "u32",
-               "INT64" => "i64", 
-               "UINT64" => "u64",
-];
-
-printf("\tswitch (t1) { \\\n");
-foreach ($types as $t1 => $f1) {
-       printf("\tcase PSI_T_%s: \\\n", $t1);
-       printf("\t\tswitch (t2) { \\\n");
-       foreach ($types as $t2 => $f2) {
-               printf("\t\tcase PSI_T_%s:\tPSI_CALC_OP2(u8, %s, %s);\tbreak; \\\n",
-                               $t2, $f1, $f2);
-       }
-       printf("\t\tEMPTY_SWITCH_DEFAULT_CASE(); \\\n\t\t} \\\n\t\tbreak; \\\n");
-}
-printf("\tEMPTY_SWITCH_DEFAULT_CASE(); \\\n\t} \\\n");
\ No newline at end of file
diff --git a/scripts/gen_int.php b/scripts/gen_int.php
deleted file mode 100644 (file)
index 2df05ed..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-$types = [
-               "INT8" => "i8",
-               "UINT8" => "u8",
-               "INT16" => "i16", 
-               "UINT16" => "u16",
-               "INT32" => "i32", 
-               "UINT32" => "u32",
-               "INT64" => "i64", 
-               "UINT64" => "u64",
-];
-
-printf("\tswitch (t1) { \\\n");
-foreach ($types as $t1 => $f1) {
-       $s1 = substr($f1, 1);
-       $u1 = $f1{0} == "u";
-       printf("\tcase PSI_T_%s: \\\n", $t1);
-       printf("\t\tswitch (t2) { \\\n");
-       foreach ($types as $t2 => $f2) {
-               $s2 = substr($f2, 1);
-               $u2 = $f2{0} == "u";
-               
-               if ($u1 && $u2)  {
-                       $fr = "u".min(64,max($s1*2,$s2*2));
-               } else {
-                       $fr = "i".min(64,max($s1*2,$s2*2));
-               }
-               
-               printf("\t\tcase PSI_T_%s:\tPSI_CALC_OP2(%s, %s, %s);\treturn PSI_T_%s; \\\n",
-                               $t2, $fr, $f1, $f2, str_replace(["u","i"], ["UINT","INT"], $fr));
-       }
-       printf("\t\tEMPTY_SWITCH_DEFAULT_CASE(); \\\n\t\t} \\\n\t\tbreak; \\\n");
-}
-printf("\tEMPTY_SWITCH_DEFAULT_CASE(); \\\n\t} \\\n");
\ No newline at end of file
diff --git a/scripts/gen_oper.php b/scripts/gen_oper.php
deleted file mode 100644 (file)
index e35bc4b..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- Copyright (c) 2016, Michael Wallner <mike@php.net>.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
-     * Redistributions of source code must retain the above copyright notice,
-       this list of conditions and the following disclaimer.
-     * Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************/
-
-static inline int psi_token_oper_cmp(token_t op1, token_t op2) {
-       switch (op1) {
-<?php
-
-$oper = [
-               ["NOT", "TILDE"],
-               ["ASTERISK", "SLASH", "MODULO"],
-               ["PLUS", "MINUS"],
-               ["LSHIFT", "RSHIFT"],
-               ["LCHEVR", "CMP_LE", "RCHEVR", "CMP_GE"],
-               ["AMPERSAND"],
-               ["CMP_EQ", "CMP_NE"],
-               ["CARET"],
-               ["PIPE"],
-               ["AND"],
-               ["OR"]
-];
-
-
-foreach ($oper as $prec1 => $ops1) {
-       foreach ($ops1 as $op1) {
-               printf("\tcase PSI_T_%s:\n", $op1);
-               printf("\t\tswitch (op2) {\n");
-               foreach ($oper as $prec2 => $ops2) {
-                       foreach ($ops2 as $op2) {
-                               printf("\t\t\tcase PSI_T_%s: %sreturn %2d;\n", $op2,
-                                               str_repeat(" ", 10 - strlen($op2)),
-                                               $prec1==$prec2?0:($prec1>$prec2?1:-1));
-                       }
-               }
-               printf("\t\t}\n\t\tassert(0);\n\t\tbreak;\n");
-       }
-}
-?>
-       }
-       assert(0);
-       return 0;
-}
diff --git a/src/calc.c b/src/calc.c
deleted file mode 100644 (file)
index 2dc85f4..0000000
+++ /dev/null
@@ -1,638 +0,0 @@
-/*******************************************************************************
- Copyright (c) 2016, Michael Wallner <mike@php.net>.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
-     * Redistributions of source code must retain the above copyright notice,
-       this list of conditions and the following disclaimer.
-     * Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************/
-
-#include "php_psi_stdinc.h"
-#include <assert.h>
-
-#include "token.h"
-#include "calc.h"
-
-#define PSI_CALC_CAST_SET(in_type, in_val, op, out_val, out_var) \
-switch (in_type) { \
-case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
-case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
-case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
-case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
-case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
-case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
-case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
-case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
-case PSI_T_FLOAT:              (out_val)->out_var op (in_val)->fval;   break; \
-case PSI_T_DOUBLE:             (out_val)->out_var op (in_val)->dval;   break; \
-case PSI_T_LONG_DOUBLE:        (out_val)->out_var op (in_val)->ldval;  break; \
-default: \
-       assert(0); \
-}
-
-#define PSI_CALC_CAST(in_type, in_val, op, out_type, out_val) \
-switch (out_type) { \
-case PSI_T_INT8:               PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i8)             break; \
-case PSI_T_UINT8:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u8)             break; \
-case PSI_T_INT16:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i16)    break; \
-case PSI_T_UINT16:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u16)    break; \
-case PSI_T_INT32:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i32)    break; \
-case PSI_T_UINT32:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u32)    break; \
-case PSI_T_INT64:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i64)    break; \
-case PSI_T_UINT64:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u64)    break; \
-case PSI_T_FLOAT:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, fval)   break; \
-case PSI_T_DOUBLE:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, dval)   break; \
-case PSI_T_LONG_DOUBLE:        PSI_CALC_CAST_SET(in_type, in_val, op, out_val, ldval)  break; \
-default: \
-       assert(0); \
-}
-
-#define PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, out_var) \
-switch (in_type) { \
-case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
-case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
-case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
-case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
-case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
-case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
-case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
-case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
-default: \
-       assert(0); \
-}
-#define PSI_CALC_CAST_INT(in_type, in_val, op, out_type, out_val) \
-switch (out_type) { \
-case PSI_T_INT8:               PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i8)         break; \
-case PSI_T_UINT8:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u8)         break; \
-case PSI_T_INT16:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i16)        break; \
-case PSI_T_UINT16:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u16)        break; \
-case PSI_T_INT32:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i32)        break; \
-case PSI_T_UINT32:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u32)        break; \
-case PSI_T_INT64:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i64)        break; \
-case PSI_T_UINT64:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u64)        break; \
-default: \
-       assert(0); \
-}
-
-void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
-{
-       PSI_CALC_CAST(in_type, in_val, =, out_type, out_val)
-}
-
-#if 0
-#define PSI_CALC_OP(var) do { \
-       const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
-       res->var = PSI_CALC(v1->var, v2->var); \
-       if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
-} while (0)
-#define PSI_CALC_OP2(vres, var1, var2) do { \
-       const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
-       res->vres = PSI_CALC(v1->var1, v2->var2); \
-       if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
-} while(0)
-#else
-#define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
-#define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
-#endif
-
-#ifdef HAVE_LONG_DOUBLE
-# define PSI_CALC_NO_LD
-# define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
-# define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
-# define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
-#else
-# define PSI_CALC_NO_LD abort()
-# define PSI_CALC_OP_LD PSI_CALC_NO_LD
-# define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
-# define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
-#endif
-
-#define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
-{ \
-       if (t1 == t2) { \
-               switch (t1) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP(fval);      break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP(dval);      break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
-               case PSI_T_INT8:        PSI_CALC_OP(i8);        break; \
-               case PSI_T_UINT8:       PSI_CALC_OP(u8);        break; \
-               case PSI_T_INT16:       PSI_CALC_OP(i16);       break; \
-               case PSI_T_UINT16:      PSI_CALC_OP(u16);       break; \
-               case PSI_T_INT32:       PSI_CALC_OP(i32);       break; \
-               case PSI_T_UINT32:      PSI_CALC_OP(u32);       break; \
-               case PSI_T_INT64:       PSI_CALC_OP(i64);       break; \
-               case PSI_T_UINT64:      PSI_CALC_OP(u64);       break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t1; \
-       } else if (t1 == PSI_T_DOUBLE) { \
-               switch (t2) { \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval);         return t2; \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(dval, dval, fval); break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(dval, dval, i8);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(dval, dval, u8);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(dval, dval, i16);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(dval, dval, u16);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(dval, dval, i32);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(dval, dval, u32);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(dval, dval, i64);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(dval, dval, u64);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t1; \
-       } else if (t2 == PSI_T_DOUBLE) { \
-               switch (t1) { \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval);         return t1; \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(dval, fval, dval); break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(dval, i8, dval);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(dval, u8, dval);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(dval, i16, dval);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(dval, u16, dval);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(dval, i32, dval);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(dval, u32, dval);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(dval, i64, dval);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(dval, u64, dval);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t2; \
-       } else if (t1 == PSI_T_LONG_DOUBLE) { \
-               PSI_CALC_NO_LD; \
-               switch (t2) { \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2_LD1(dval); break; \
-               case PSI_T_FLOAT:       PSI_CALC_OP2_LD1(fval); break; \
-               case PSI_T_INT8:        PSI_CALC_OP2_LD1(i8);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2_LD1(u8);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2_LD1(i16);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2_LD1(u16);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2_LD1(i32);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2_LD1(u32);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2_LD1(i64);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2_LD1(u64);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t1; \
-       } else if (t2 == PSI_T_LONG_DOUBLE) { \
-               PSI_CALC_NO_LD; \
-               switch (t1) { \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2_LD2(dval); break; \
-               case PSI_T_FLOAT:       PSI_CALC_OP2_LD2(fval); break; \
-               case PSI_T_INT8:        PSI_CALC_OP2_LD2(i8);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2_LD2(u8);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2_LD2(i16);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2_LD2(u16);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2_LD2(i32);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2_LD2(u32);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2_LD2(i64);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2_LD2(u64);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t2; \
-       } else if (t1 == PSI_T_FLOAT) { \
-               switch (t2) { \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval);         return t2; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(dval, fval, dval); return t2; \
-               case PSI_T_INT8:        PSI_CALC_OP2(fval, fval, i8);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(fval, fval, u8);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(fval, fval, i16);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(fval, fval, u16);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(fval, fval, i32);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(fval, fval, u32);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(fval, fval, i64);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(fval, fval, u64);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t1; \
-       } else if (t2 == PSI_T_FLOAT) { \
-               switch (t1) { \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval);         return t1; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(dval, dval, fval); return t1; \
-               case PSI_T_INT8:        PSI_CALC_OP2(fval, i8, fval);   break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(fval, u8, fval);   break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(fval, i16, fval);  break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(fval, u16, fval);  break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(fval, i32, fval);  break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(fval, u32, fval);  break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(fval, i64, fval);  break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(fval, u64, fval);  break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               return t2; \
-       } else { \
-               switch (t1) { \
-               case PSI_T_INT8: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i16, i8, i8);      return PSI_T_INT16; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(i16, i8, u8);      return PSI_T_INT16; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i32, i8, i16);     return PSI_T_INT32; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(i32, i8, u16);     return PSI_T_INT32; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, i8, i32);     return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(i64, i8, u32);     return PSI_T_INT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, i8, i64);     return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(i64, i8, u64);     return PSI_T_INT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_UINT8: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i16, u8, i8);      return PSI_T_INT16; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(u16, u8, u8);      return PSI_T_UINT16; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i32, u8, i16);     return PSI_T_INT32; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(u32, u8, u16);     return PSI_T_UINT32; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, u8, i32);     return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(u64, u8, u32);     return PSI_T_UINT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, u8, i64);     return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(u64, u8, u64);     return PSI_T_UINT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_INT16: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i32, i16, i8);     return PSI_T_INT32; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(i32, i16, u8);     return PSI_T_INT32; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i32, i16, i16);    return PSI_T_INT32; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(i32, i16, u16);    return PSI_T_INT32; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, i16, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(i64, i16, u32);    return PSI_T_INT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, i16, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(i64, i16, u64);    return PSI_T_INT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_UINT16: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i32, u16, i8);     return PSI_T_INT32; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(u32, u16, u8);     return PSI_T_UINT32; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i32, u16, i16);    return PSI_T_INT32; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(u32, u16, u16);    return PSI_T_UINT32; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, u16, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(u64, u16, u32);    return PSI_T_UINT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, u16, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(u64, u16, u64);    return PSI_T_UINT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_INT32: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i64, i32, i8);     return PSI_T_INT64; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(i64, i32, u8);     return PSI_T_INT64; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i64, i32, i16);    return PSI_T_INT64; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(i64, i32, u16);    return PSI_T_INT64; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, i32, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(i64, i32, u32);    return PSI_T_INT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, i32, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(i64, i32, u64);    return PSI_T_INT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_UINT32: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i64, u32, i8);     return PSI_T_INT64; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(u64, u32, u8);     return PSI_T_UINT64; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i64, u32, i16);    return PSI_T_INT64; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(u64, u32, u16);    return PSI_T_UINT64; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, u32, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(u64, u32, u32);    return PSI_T_UINT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, u32, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(u64, u32, u64);    return PSI_T_UINT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_INT64: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i64, i64, i8);     return PSI_T_INT64; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(i64, i64, u8);     return PSI_T_INT64; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i64, i64, i16);    return PSI_T_INT64; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(i64, i64, u16);    return PSI_T_INT64; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, i64, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(i64, i64, u32);    return PSI_T_INT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, i64, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(i64, i64, u64);    return PSI_T_INT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               case PSI_T_UINT64: \
-                       switch (t2) { \
-                       case PSI_T_INT8:        PSI_CALC_OP2(i64, u64, i8);     return PSI_T_INT64; \
-                       case PSI_T_UINT8:       PSI_CALC_OP2(u64, u64, u8);     return PSI_T_UINT64; \
-                       case PSI_T_INT16:       PSI_CALC_OP2(i64, u64, i16);    return PSI_T_INT64; \
-                       case PSI_T_UINT16:      PSI_CALC_OP2(u64, u64, u16);    return PSI_T_UINT64; \
-                       case PSI_T_INT32:       PSI_CALC_OP2(i64, u64, i32);    return PSI_T_INT64; \
-                       case PSI_T_UINT32:      PSI_CALC_OP2(u64, u64, u32);    return PSI_T_UINT64; \
-                       case PSI_T_INT64:       PSI_CALC_OP2(i64, u64, i64);    return PSI_T_INT64; \
-                       case PSI_T_UINT64:      PSI_CALC_OP2(u64, u64, u64);    return PSI_T_UINT64; \
-                       EMPTY_SWITCH_DEFAULT_CASE(); \
-                       } \
-                       break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-       } \
-       assert(0); \
-       return 0; \
-}
-
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) + (var2)
-PSI_CALC_FN(add)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) * (var2)
-PSI_CALC_FN(mul)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) - (var2)
-PSI_CALC_FN(sub)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) / (var2)
-PSI_CALC_FN(div)
-#undef PSI_CALC
-
-token_t psi_calc_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
-{
-       impl_val i1, i2;
-
-       PSI_CALC_CAST(t1, v1, =, PSI_T_INT64, &i1);
-       PSI_CALC_CAST(t2, v2, =, PSI_T_INT64, &i2);
-
-       res->i64 = i1.i64 % i2.i64;
-
-       return PSI_T_INT64;
-}
-
-#define PSI_CALC_BIT_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
-{ \
-       impl_val i1, i2; \
-       PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1); \
-       PSI_CALC_CAST(t2, v2, =, PSI_T_UINT64, &i2); \
-       res->u64 = PSI_CALC(i1.u64, i2.u64); \
-       return PSI_T_UINT64; \
-}
-
-#define PSI_CALC(var1, var2) (var1) << (var2)
-PSI_CALC_BIT_FN(bin_lshift)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) >> (var2)
-PSI_CALC_BIT_FN(bin_rshift)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) & (var2)
-PSI_CALC_BIT_FN(bin_and)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) ^ (var2)
-PSI_CALC_BIT_FN(bin_xor)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) | (var2)
-PSI_CALC_BIT_FN(bin_or)
-#undef PSI_CALC
-
-#define PSI_CALC_CMP_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
-{ \
-       switch (t1) { \
-       case PSI_T_FLOAT: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, fval, fval);   break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, fval, dval);   break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, fval, ldval);  break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, fval, i8);     break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, fval, u8);     break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, fval, i16);    break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, fval, u16);    break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, fval, i32);    break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, fval, u32);    break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, fval, i64);    break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, fval, u64);    break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_DOUBLE: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, dval, fval);   break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, dval, dval);   break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, dval, ldval);  break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, dval, i8);     break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, dval, u8);     break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, dval, i16);    break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, dval, u16);    break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, dval, i32);    break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, dval, u32);    break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, dval, i64);    break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, dval, u64);    break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_LONG_DOUBLE: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, ldval, fval);  break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, ldval, dval);  break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, ldval, ldval); break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, ldval, i8);    break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, ldval, u8);    break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, ldval, i16);   break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, ldval, u16);   break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, ldval, i32);   break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, ldval, u32);   break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, ldval, i64);   break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, ldval, u64);   break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_INT8: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, i8, fval);     break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, i8, dval);     break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, i8, ldval);    break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, i8, i8);       break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, i8, u8);       break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, i8, i16);      break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, i8, u16);      break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, i8, i32);      break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, i8, u32);      break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, i8, i64);      break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, i8, u64);      break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_UINT8: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, u8, fval);     break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, u8, dval);     break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, u8, ldval);    break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, u8, i8);       break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, u8, u8);       break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, u8, i16);      break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, u8, u16);      break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, u8, i32);      break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, u8, u32);      break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, u8, i64);      break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, u8, u64);      break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_INT16: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, i16, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, i16, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, i16, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, i16, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, i16, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, i16, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, i16, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, i16, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, i16, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, i16, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, i16, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_UINT16: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, u16, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, u16, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, u16, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, u16, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, u16, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, u16, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, u16, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, u16, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, u16, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, u16, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, u16, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_INT32: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, i32, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, i32, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, i32, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, i32, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, i32, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, i32, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, i32, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, i32, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, i32, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, i32, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, i32, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_UINT32: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, u32, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, u32, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, u32, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, u32, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, u32, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, u32, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, u32, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, u32, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, u32, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, u32, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, u32, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_INT64: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, i64, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, i64, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, i64, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, i64, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, i64, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, i64, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, i64, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, i64, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, i64, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, i64, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, i64, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       case PSI_T_UINT64: \
-               switch (t2) { \
-               case PSI_T_FLOAT:       PSI_CALC_OP2(u8, u64, fval);    break; \
-               case PSI_T_DOUBLE:      PSI_CALC_OP2(u8, u64, dval);    break; \
-               case PSI_T_LONG_DOUBLE: PSI_CALC_OP2(u8, u64, ldval);   break; \
-               case PSI_T_INT8:        PSI_CALC_OP2(u8, u64, i8);      break; \
-               case PSI_T_UINT8:       PSI_CALC_OP2(u8, u64, u8);      break; \
-               case PSI_T_INT16:       PSI_CALC_OP2(u8, u64, i16);     break; \
-               case PSI_T_UINT16:      PSI_CALC_OP2(u8, u64, u16);     break; \
-               case PSI_T_INT32:       PSI_CALC_OP2(u8, u64, i32);     break; \
-               case PSI_T_UINT32:      PSI_CALC_OP2(u8, u64, u32);     break; \
-               case PSI_T_INT64:       PSI_CALC_OP2(u8, u64, i64);     break; \
-               case PSI_T_UINT64:      PSI_CALC_OP2(u8, u64, u64);     break; \
-               EMPTY_SWITCH_DEFAULT_CASE(); \
-               } \
-               break; \
-       EMPTY_SWITCH_DEFAULT_CASE(); \
-       } \
-       return PSI_T_UINT8; \
-}
-
-#define PSI_CALC(var1, var2) (var1) == (var2)
-PSI_CALC_CMP_FN(cmp_eq)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) != (var2)
-PSI_CALC_CMP_FN(cmp_ne)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) <= (var2)
-PSI_CALC_CMP_FN(cmp_le)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) >= (var2)
-PSI_CALC_CMP_FN(cmp_ge)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) < (var2)
-PSI_CALC_CMP_FN(cmp_lt)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) > (var2)
-PSI_CALC_CMP_FN(cmp_gt)
-#undef PSI_CALC
-
-#define PSI_CALC_BOOL_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
-{ \
-       impl_val i1, i2; \
-       PSI_CALC_CAST(t1, v1, =!!, PSI_T_UINT8, &i1); \
-       PSI_CALC_CAST(t2, v2, =!!, PSI_T_UINT8, &i2); \
-       res->u8 = PSI_CALC(i1.u8, i2.u8); \
-       return PSI_T_UINT8; \
-}
-
-#define PSI_CALC(var1, var2) (var1) && (var2)
-PSI_CALC_BOOL_FN(and)
-#undef PSI_CALC
-#define PSI_CALC(var1, var2) (var1) || (var2)
-PSI_CALC_BOOL_FN(or)
-#undef PSI_CALC
-
-token_t psi_calc_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
-{
-       (void) t2;
-       (void) v2;
-
-       PSI_CALC_CAST(t1, v1, =!, t1, res);
-       return t1;
-}
-
-token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
-{
-       impl_val i1;
-
-       (void) t2;
-       (void) v2;
-
-       PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1);
-       PSI_CALC_CAST_INT(t1, &i1, =~, t1, res);
-       return t1;
-}
index dbbb116..49114ef 100644 (file)
 
 typedef token_t (*psi_calc)(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
 
-token_t psi_calc_add(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_sub(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_mul(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_div(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-
-token_t psi_calc_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-
-token_t psi_calc_bin_lshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_bin_rshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_bin_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_bin_xor(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_bin_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-
-token_t psi_calc_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-
-token_t psi_calc_cmp_eq(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_cmp_ne(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_cmp_le(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_cmp_ge(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_cmp_lt(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-token_t psi_calc_cmp_gt(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
-
-void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val);
+#include "calc/basic.h"
+#include "calc/bin.h"
+#include "calc/bool.h"
+#include "calc/cast.h"
+#include "calc/cmp.h"
+#include "calc/oper.h"
 
 #endif
diff --git a/src/calc/basic.h b/src/calc/basic.h
new file mode 100644 (file)
index 0000000..ac021e0
--- /dev/null
@@ -0,0 +1,2082 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
+
+static inline token_t psi_calc_add(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->i8 + v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->i16 = v1->i8 + v2->u8;
+                       return PSI_T_INT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->i8 + v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i8 + v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i8 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i8 + v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i8 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i8 + v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i8 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i8 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i8 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->u8 + v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->u16 = v1->u8 + v2->u8;
+                       return PSI_T_UINT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->u8 + v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u8 + v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u8 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u8 + v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u8 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u8 + v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u8 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u8 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u8 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->i16 + v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->i32 = v1->i16 + v2->u8;
+                       return PSI_T_INT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->i16 + v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i16 + v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i16 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i16 + v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i16 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i16 + v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i16 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i16 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i16 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->u16 + v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->u32 = v1->u16 + v2->u8;
+                       return PSI_T_UINT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->u16 + v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u16 + v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u16 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u16 + v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u16 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u16 + v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u16 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u16 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u16 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i32 + v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i32 + v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i32 + v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i32 + v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i32 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i32 + v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i32 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i32 + v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i32 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i32 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i32 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u32 + v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u32 + v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u32 + v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u32 + v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u32 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u32 + v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u32 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u32 + v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u32 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u32 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u32 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i64 + v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i64 + v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i64 + v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i64 + v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i64 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i64 + v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i64 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i64 + v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i64 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i64 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i64 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u64 + v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u64 + v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u64 + v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u64 + v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u64 + v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u64 + v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u64 + v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u64 + v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u64 + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u64 + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u64 + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->fval = v1->fval + v2->i8;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT8:
+                       res->fval = v1->fval + v2->u8;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT16:
+                       res->fval = v1->fval + v2->i16;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT16:
+                       res->fval = v1->fval + v2->u16;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT32:
+                       res->fval = v1->fval + v2->i32;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT32:
+                       res->fval = v1->fval + v2->u32;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT64:
+                       res->fval = v1->fval + v2->i64;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT64:
+                       res->fval = v1->fval + v2->u64;
+                       return PSI_T_FLOAT;
+               case PSI_T_FLOAT:
+                       res->fval = v1->fval + v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->fval + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->fval + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->dval = v1->dval + v2->i8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT8:
+                       res->dval = v1->dval + v2->u8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT16:
+                       res->dval = v1->dval + v2->i16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT16:
+                       res->dval = v1->dval + v2->u16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT32:
+                       res->dval = v1->dval + v2->i32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT32:
+                       res->dval = v1->dval + v2->u32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT64:
+                       res->dval = v1->dval + v2->i64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT64:
+                       res->dval = v1->dval + v2->u64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->dval = v1->dval + v2->fval;
+                       return PSI_T_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->dval + v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->dval + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->ldval = v1->ldval + v2->i8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT8:
+                       res->ldval = v1->ldval + v2->u8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT16:
+                       res->ldval = v1->ldval + v2->i16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT16:
+                       res->ldval = v1->ldval + v2->u16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT32:
+                       res->ldval = v1->ldval + v2->i32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT32:
+                       res->ldval = v1->ldval + v2->u32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT64:
+                       res->ldval = v1->ldval + v2->i64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT64:
+                       res->ldval = v1->ldval + v2->u64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->ldval = v1->ldval + v2->fval;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->ldval = v1->ldval + v2->dval;
+                       return PSI_T_LONG_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->ldval + v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return 0;
+}
+static inline token_t psi_calc_sub(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->i8 - v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->i16 = v1->i8 - v2->u8;
+                       return PSI_T_INT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->i8 - v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i8 - v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i8 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i8 - v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i8 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i8 - v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i8 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i8 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i8 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->u8 - v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->u16 = v1->u8 - v2->u8;
+                       return PSI_T_UINT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->u8 - v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u8 - v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u8 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u8 - v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u8 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u8 - v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u8 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u8 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u8 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->i16 - v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->i32 = v1->i16 - v2->u8;
+                       return PSI_T_INT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->i16 - v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i16 - v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i16 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i16 - v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i16 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i16 - v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i16 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i16 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i16 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->u16 - v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->u32 = v1->u16 - v2->u8;
+                       return PSI_T_UINT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->u16 - v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u16 - v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u16 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u16 - v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u16 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u16 - v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u16 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u16 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u16 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i32 - v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i32 - v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i32 - v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i32 - v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i32 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i32 - v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i32 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i32 - v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i32 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i32 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i32 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u32 - v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u32 - v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u32 - v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u32 - v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u32 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u32 - v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u32 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u32 - v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u32 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u32 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u32 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i64 - v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i64 - v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i64 - v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i64 - v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i64 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i64 - v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i64 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i64 - v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i64 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i64 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i64 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u64 - v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u64 - v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u64 - v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u64 - v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u64 - v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u64 - v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u64 - v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u64 - v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u64 - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u64 - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u64 - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->fval = v1->fval - v2->i8;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT8:
+                       res->fval = v1->fval - v2->u8;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT16:
+                       res->fval = v1->fval - v2->i16;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT16:
+                       res->fval = v1->fval - v2->u16;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT32:
+                       res->fval = v1->fval - v2->i32;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT32:
+                       res->fval = v1->fval - v2->u32;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT64:
+                       res->fval = v1->fval - v2->i64;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT64:
+                       res->fval = v1->fval - v2->u64;
+                       return PSI_T_FLOAT;
+               case PSI_T_FLOAT:
+                       res->fval = v1->fval - v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->fval - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->fval - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->dval = v1->dval - v2->i8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT8:
+                       res->dval = v1->dval - v2->u8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT16:
+                       res->dval = v1->dval - v2->i16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT16:
+                       res->dval = v1->dval - v2->u16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT32:
+                       res->dval = v1->dval - v2->i32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT32:
+                       res->dval = v1->dval - v2->u32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT64:
+                       res->dval = v1->dval - v2->i64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT64:
+                       res->dval = v1->dval - v2->u64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->dval = v1->dval - v2->fval;
+                       return PSI_T_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->dval - v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->dval - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->ldval = v1->ldval - v2->i8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT8:
+                       res->ldval = v1->ldval - v2->u8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT16:
+                       res->ldval = v1->ldval - v2->i16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT16:
+                       res->ldval = v1->ldval - v2->u16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT32:
+                       res->ldval = v1->ldval - v2->i32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT32:
+                       res->ldval = v1->ldval - v2->u32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT64:
+                       res->ldval = v1->ldval - v2->i64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT64:
+                       res->ldval = v1->ldval - v2->u64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->ldval = v1->ldval - v2->fval;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->ldval = v1->ldval - v2->dval;
+                       return PSI_T_LONG_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->ldval - v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return 0;
+}
+static inline token_t psi_calc_mul(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->i8 * v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->i16 = v1->i8 * v2->u8;
+                       return PSI_T_INT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->i8 * v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i8 * v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i8 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i8 * v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i8 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i8 * v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i8 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i8 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i8 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->u8 * v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->u16 = v1->u8 * v2->u8;
+                       return PSI_T_UINT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->u8 * v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u8 * v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u8 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u8 * v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u8 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u8 * v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u8 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u8 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u8 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->i16 * v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->i32 = v1->i16 * v2->u8;
+                       return PSI_T_INT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->i16 * v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i16 * v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i16 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i16 * v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i16 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i16 * v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i16 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i16 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i16 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->u16 * v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->u32 = v1->u16 * v2->u8;
+                       return PSI_T_UINT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->u16 * v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u16 * v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u16 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u16 * v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u16 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u16 * v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u16 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u16 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u16 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i32 * v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i32 * v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i32 * v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i32 * v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i32 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i32 * v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i32 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i32 * v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i32 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i32 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i32 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u32 * v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u32 * v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u32 * v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u32 * v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u32 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u32 * v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u32 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u32 * v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u32 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u32 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u32 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i64 * v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i64 * v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i64 * v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i64 * v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i64 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i64 * v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i64 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i64 * v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i64 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i64 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i64 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u64 * v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u64 * v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u64 * v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u64 * v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u64 * v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u64 * v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u64 * v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u64 * v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u64 * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u64 * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u64 * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->fval = v1->fval * v2->i8;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT8:
+                       res->fval = v1->fval * v2->u8;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT16:
+                       res->fval = v1->fval * v2->i16;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT16:
+                       res->fval = v1->fval * v2->u16;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT32:
+                       res->fval = v1->fval * v2->i32;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT32:
+                       res->fval = v1->fval * v2->u32;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT64:
+                       res->fval = v1->fval * v2->i64;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT64:
+                       res->fval = v1->fval * v2->u64;
+                       return PSI_T_FLOAT;
+               case PSI_T_FLOAT:
+                       res->fval = v1->fval * v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->fval * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->fval * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->dval = v1->dval * v2->i8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT8:
+                       res->dval = v1->dval * v2->u8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT16:
+                       res->dval = v1->dval * v2->i16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT16:
+                       res->dval = v1->dval * v2->u16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT32:
+                       res->dval = v1->dval * v2->i32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT32:
+                       res->dval = v1->dval * v2->u32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT64:
+                       res->dval = v1->dval * v2->i64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT64:
+                       res->dval = v1->dval * v2->u64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->dval = v1->dval * v2->fval;
+                       return PSI_T_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->dval * v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->dval * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->ldval = v1->ldval * v2->i8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT8:
+                       res->ldval = v1->ldval * v2->u8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT16:
+                       res->ldval = v1->ldval * v2->i16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT16:
+                       res->ldval = v1->ldval * v2->u16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT32:
+                       res->ldval = v1->ldval * v2->i32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT32:
+                       res->ldval = v1->ldval * v2->u32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT64:
+                       res->ldval = v1->ldval * v2->i64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT64:
+                       res->ldval = v1->ldval * v2->u64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->ldval = v1->ldval * v2->fval;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->ldval = v1->ldval * v2->dval;
+                       return PSI_T_LONG_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->ldval * v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return 0;
+}
+static inline token_t psi_calc_div(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->i8 / v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->i16 = v1->i8 / v2->u8;
+                       return PSI_T_INT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->i8 / v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i8 / v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i8 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i8 / v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i8 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i8 / v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i8 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i8 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i8 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i16 = v1->u8 / v2->i8;
+                       return PSI_T_INT16;
+               case PSI_T_UINT8:
+                       res->u16 = v1->u8 / v2->u8;
+                       return PSI_T_UINT16;
+               case PSI_T_INT16:
+                       res->i32 = v1->u8 / v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u8 / v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u8 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u8 / v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u8 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u8 / v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u8 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u8 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u8 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->i16 / v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->i32 = v1->i16 / v2->u8;
+                       return PSI_T_INT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->i16 / v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->i32 = v1->i16 / v2->u16;
+                       return PSI_T_INT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->i16 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i16 / v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i16 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i16 / v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i16 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i16 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i16 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i32 = v1->u16 / v2->i8;
+                       return PSI_T_INT32;
+               case PSI_T_UINT8:
+                       res->u32 = v1->u16 / v2->u8;
+                       return PSI_T_UINT32;
+               case PSI_T_INT16:
+                       res->i32 = v1->u16 / v2->i16;
+                       return PSI_T_INT32;
+               case PSI_T_UINT16:
+                       res->u32 = v1->u16 / v2->u16;
+                       return PSI_T_UINT32;
+               case PSI_T_INT32:
+                       res->i64 = v1->u16 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u16 / v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u16 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u16 / v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u16 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u16 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u16 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i32 / v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i32 / v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i32 / v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i32 / v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i32 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i32 / v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i32 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i32 / v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i32 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i32 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i32 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u32 / v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u32 / v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u32 / v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u32 / v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u32 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u32 / v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u32 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u32 / v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u32 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u32 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u32 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->i64 / v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->i64 = v1->i64 / v2->u8;
+                       return PSI_T_INT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->i64 / v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->i64 = v1->i64 / v2->u16;
+                       return PSI_T_INT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->i64 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->i64 = v1->i64 / v2->u32;
+                       return PSI_T_INT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->i64 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->i64 = v1->i64 / v2->u64;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->i64 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->i64 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->i64 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->i64 = v1->u64 / v2->i8;
+                       return PSI_T_INT64;
+               case PSI_T_UINT8:
+                       res->u64 = v1->u64 / v2->u8;
+                       return PSI_T_UINT64;
+               case PSI_T_INT16:
+                       res->i64 = v1->u64 / v2->i16;
+                       return PSI_T_INT64;
+               case PSI_T_UINT16:
+                       res->u64 = v1->u64 / v2->u16;
+                       return PSI_T_UINT64;
+               case PSI_T_INT32:
+                       res->i64 = v1->u64 / v2->i32;
+                       return PSI_T_INT64;
+               case PSI_T_UINT32:
+                       res->u64 = v1->u64 / v2->u32;
+                       return PSI_T_UINT64;
+               case PSI_T_INT64:
+                       res->i64 = v1->u64 / v2->i64;
+                       return PSI_T_INT64;
+               case PSI_T_UINT64:
+                       res->u64 = v1->u64 / v2->u64;
+                       return PSI_T_UINT64;
+               case PSI_T_FLOAT:
+                       res->fval = v1->u64 / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->u64 / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->u64 / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->fval = v1->fval / v2->i8;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT8:
+                       res->fval = v1->fval / v2->u8;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT16:
+                       res->fval = v1->fval / v2->i16;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT16:
+                       res->fval = v1->fval / v2->u16;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT32:
+                       res->fval = v1->fval / v2->i32;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT32:
+                       res->fval = v1->fval / v2->u32;
+                       return PSI_T_FLOAT;
+               case PSI_T_INT64:
+                       res->fval = v1->fval / v2->i64;
+                       return PSI_T_FLOAT;
+               case PSI_T_UINT64:
+                       res->fval = v1->fval / v2->u64;
+                       return PSI_T_FLOAT;
+               case PSI_T_FLOAT:
+                       res->fval = v1->fval / v2->fval;
+                       return PSI_T_FLOAT;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->fval / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->fval / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->dval = v1->dval / v2->i8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT8:
+                       res->dval = v1->dval / v2->u8;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT16:
+                       res->dval = v1->dval / v2->i16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT16:
+                       res->dval = v1->dval / v2->u16;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT32:
+                       res->dval = v1->dval / v2->i32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT32:
+                       res->dval = v1->dval / v2->u32;
+                       return PSI_T_DOUBLE;
+               case PSI_T_INT64:
+                       res->dval = v1->dval / v2->i64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_UINT64:
+                       res->dval = v1->dval / v2->u64;
+                       return PSI_T_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->dval = v1->dval / v2->fval;
+                       return PSI_T_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->dval = v1->dval / v2->dval;
+                       return PSI_T_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->dval / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->ldval = v1->ldval / v2->i8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT8:
+                       res->ldval = v1->ldval / v2->u8;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT16:
+                       res->ldval = v1->ldval / v2->i16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT16:
+                       res->ldval = v1->ldval / v2->u16;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT32:
+                       res->ldval = v1->ldval / v2->i32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT32:
+                       res->ldval = v1->ldval / v2->u32;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_INT64:
+                       res->ldval = v1->ldval / v2->i64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_UINT64:
+                       res->ldval = v1->ldval / v2->u64;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_FLOAT:
+                       res->ldval = v1->ldval / v2->fval;
+                       return PSI_T_LONG_DOUBLE;
+               case PSI_T_DOUBLE:
+                       res->ldval = v1->ldval / v2->dval;
+                       return PSI_T_LONG_DOUBLE;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->ldval = v1->ldval / v2->ldval;
+                       return PSI_T_LONG_DOUBLE;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return 0;
+}
+
+
+static inline token_t psi_calc_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.i64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.i64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.i64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.i64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.i64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.i64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.i64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.i64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.i64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.i64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.i64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.i64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.i64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.i64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.i64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.i64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.i64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.i64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.i64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.i64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.i64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.i64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->i64 = i1.i64 % i2.i64;
+       return PSI_T_INT64;
+}
diff --git a/src/calc/bin.h b/src/calc/bin.h
new file mode 100644 (file)
index 0000000..3e9e4a0
--- /dev/null
@@ -0,0 +1,608 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
+
+static inline token_t psi_calc_bin_lshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.u64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.u64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.u64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.u64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.u64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.u64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.u64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.u64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.u64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.u64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.u64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = i1.u64 << i2.u64;
+       return PSI_T_UINT64;
+}
+
+static inline token_t psi_calc_bin_rshift(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.u64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.u64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.u64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.u64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.u64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.u64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.u64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.u64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.u64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.u64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.u64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = i1.u64 >> i2.u64;
+       return PSI_T_UINT64;
+}
+
+static inline token_t psi_calc_bin_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.u64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.u64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.u64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.u64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.u64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.u64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.u64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.u64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.u64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.u64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.u64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = i1.u64 & i2.u64;
+       return PSI_T_UINT64;
+}
+
+static inline token_t psi_calc_bin_xor(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.u64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.u64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.u64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.u64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.u64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.u64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.u64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.u64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.u64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.u64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.u64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = i1.u64 ^ i2.u64;
+       return PSI_T_UINT64;
+}
+
+static inline token_t psi_calc_bin_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               i2.u64 = v2->i8;
+               break;
+       case PSI_T_UINT8:
+               i2.u64 = v2->u8;
+               break;
+       case PSI_T_INT16:
+               i2.u64 = v2->i16;
+               break;
+       case PSI_T_UINT16:
+               i2.u64 = v2->u16;
+               break;
+       case PSI_T_INT32:
+               i2.u64 = v2->i32;
+               break;
+       case PSI_T_UINT32:
+               i2.u64 = v2->u32;
+               break;
+       case PSI_T_INT64:
+               i2.u64 = v2->i64;
+               break;
+       case PSI_T_UINT64:
+               i2.u64 = v2->u64;
+               break;
+       case PSI_T_FLOAT:
+               i2.u64 = v2->fval;
+               break;
+       case PSI_T_DOUBLE:
+               i2.u64 = v2->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i2.u64 = v2->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = i1.u64 | i2.u64;
+       return PSI_T_UINT64;
+}
+
+static inline token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1;
+
+       (void) t2;
+       (void) v2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               i1.u64 = v1->i8;
+               break;
+
+       case PSI_T_UINT8:
+               i1.u64 = v1->u8;
+               break;
+
+       case PSI_T_INT16:
+               i1.u64 = v1->i16;
+               break;
+
+       case PSI_T_UINT16:
+               i1.u64 = v1->u16;
+               break;
+
+       case PSI_T_INT32:
+               i1.u64 = v1->i32;
+               break;
+
+       case PSI_T_UINT32:
+               i1.u64 = v1->u32;
+               break;
+
+       case PSI_T_INT64:
+               i1.u64 = v1->i64;
+               break;
+
+       case PSI_T_UINT64:
+               i1.u64 = v1->u64;
+               break;
+
+       case PSI_T_FLOAT:
+               i1.u64 = v1->fval;
+               break;
+
+       case PSI_T_DOUBLE:
+               i1.u64 = v1->dval;
+               break;
+
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               i1.u64 = v1->ldval;
+               break;
+
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u64 = ~i1.u64;
+       return PSI_T_UINT64;
+}
\ No newline at end of file
diff --git a/src/calc/bool.h b/src/calc/bool.h
new file mode 100644 (file)
index 0000000..99f5f0a
--- /dev/null
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
+
+static inline token_t psi_calc_bool_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       (void) t2;
+       (void) v2;
+
+       switch (t1) {
+       case PSI_T_INT8:
+               res->u8 = !v1->i8;
+               break;
+       case PSI_T_UINT8:
+               res->u8 = !v1->u8;
+               break;
+       case PSI_T_INT16:
+               res->u8 = !v1->i16;
+               break;
+       case PSI_T_UINT16:
+               res->u8 = !v1->u16;
+               break;
+       case PSI_T_INT32:
+               res->u8 = !v1->i32;
+               break;
+       case PSI_T_UINT32:
+               res->u8 = !v1->u32;
+               break;
+       case PSI_T_INT64:
+               res->u8 = !v1->i64;
+               break;
+       case PSI_T_UINT64:
+               res->u8 = !v1->u64;
+               break;
+       case PSI_T_FLOAT:
+               res->u8 = !v1->fval;
+               break;
+       case PSI_T_DOUBLE:
+               res->u8 = !v1->dval;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               res->u8 = !v1->ldval;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_bool_or(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               if (v1->i8)
+                       goto return_true;
+               break;
+       case PSI_T_UINT8:
+               if (v1->u8)
+                       goto return_true;
+               break;
+       case PSI_T_INT16:
+               if (v1->i16)
+                       goto return_true;
+               break;
+       case PSI_T_UINT16:
+               if (v1->u16)
+                       goto return_true;
+               break;
+       case PSI_T_INT32:
+               if (v1->i32)
+                       goto return_true;
+               break;
+       case PSI_T_UINT32:
+               if (v1->u32)
+                       goto return_true;
+               break;
+       case PSI_T_INT64:
+               if (v1->i64)
+                       goto return_true;
+               break;
+       case PSI_T_UINT64:
+               if (v1->u64)
+                       goto return_true;
+               break;
+       case PSI_T_FLOAT:
+               if (v1->fval)
+                       goto return_true;
+               break;
+       case PSI_T_DOUBLE:
+               if (v1->dval)
+                       goto return_true;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               if (v1->ldval)
+                       goto return_true;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               if (v2->i8)
+                       goto return_true;
+               break;
+       case PSI_T_UINT8:
+               if (v2->u8)
+                       goto return_true;
+               break;
+       case PSI_T_INT16:
+               if (v2->i16)
+                       goto return_true;
+               break;
+       case PSI_T_UINT16:
+               if (v2->u16)
+                       goto return_true;
+               break;
+       case PSI_T_INT32:
+               if (v2->i32)
+                       goto return_true;
+               break;
+       case PSI_T_UINT32:
+               if (v2->u32)
+                       goto return_true;
+               break;
+       case PSI_T_INT64:
+               if (v2->i64)
+                       goto return_true;
+               break;
+       case PSI_T_UINT64:
+               if (v2->u64)
+                       goto return_true;
+               break;
+       case PSI_T_FLOAT:
+               if (v2->fval)
+                       goto return_true;
+               break;
+       case PSI_T_DOUBLE:
+               if (v2->dval)
+                       goto return_true;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               if (v2->ldval)
+                       goto return_true;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u8 = 0;
+       return PSI_T_UINT8;
+
+return_true:
+       res->u8 = 1;
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_bool_and(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               if (!v1->i8)
+                       goto return_false;
+               break;
+       case PSI_T_UINT8:
+               if (!v1->u8)
+                       goto return_false;
+               break;
+       case PSI_T_INT16:
+               if (!v1->i16)
+                       goto return_false;
+               break;
+       case PSI_T_UINT16:
+               if (!v1->u16)
+                       goto return_false;
+               break;
+       case PSI_T_INT32:
+               if (!v1->i32)
+                       goto return_false;
+               break;
+       case PSI_T_UINT32:
+               if (!v1->u32)
+                       goto return_false;
+               break;
+       case PSI_T_INT64:
+               if (!v1->i64)
+                       goto return_false;
+               break;
+       case PSI_T_UINT64:
+               if (!v1->u64)
+                       goto return_false;
+               break;
+       case PSI_T_FLOAT:
+               if (!v1->fval)
+                       goto return_false;
+               break;
+       case PSI_T_DOUBLE:
+               if (!v1->dval)
+                       goto return_false;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               if (!v1->ldval)
+                       goto return_false;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       switch (t2) {
+       case PSI_T_INT8:
+               if (!v2->i8)
+                       goto return_false;
+               break;
+       case PSI_T_UINT8:
+               if (!v2->u8)
+                       goto return_false;
+               break;
+       case PSI_T_INT16:
+               if (!v2->i16)
+                       goto return_false;
+               break;
+       case PSI_T_UINT16:
+               if (!v2->u16)
+                       goto return_false;
+               break;
+       case PSI_T_INT32:
+               if (!v2->i32)
+                       goto return_false;
+               break;
+       case PSI_T_UINT32:
+               if (!v2->u32)
+                       goto return_false;
+               break;
+       case PSI_T_INT64:
+               if (!v2->i64)
+                       goto return_false;
+               break;
+       case PSI_T_UINT64:
+               if (!v2->u64)
+                       goto return_false;
+               break;
+       case PSI_T_FLOAT:
+               if (!v2->fval)
+                       goto return_false;
+               break;
+       case PSI_T_DOUBLE:
+               if (!v2->dval)
+                       goto return_false;
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               if (!v2->ldval)
+                       goto return_false;
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+
+       res->u8 = 1;
+       return PSI_T_UINT8;
+
+return_false:
+       res->u8 = 0;
+       return PSI_T_UINT8;
+}
diff --git a/src/calc/cast.h b/src/calc/cast.h
new file mode 100644 (file)
index 0000000..c6f14aa
--- /dev/null
@@ -0,0 +1,515 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
+
+static inline void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
+{
+       switch (out_type) {
+       case PSI_T_INT8:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->i8 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->i8 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->i8 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->i8 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->i8 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->i8 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->i8 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->i8 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->i8 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->i8 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->i8 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->u8 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->u8 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->u8 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->u8 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->u8 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->u8 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->u8 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->u8 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->u8 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->u8 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->u8 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->i16 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->i16 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->i16 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->i16 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->i16 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->i16 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->i16 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->i16 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->i16 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->i16 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->i16 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->u16 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->u16 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->u16 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->u16 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->u16 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->u16 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->u16 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->u16 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->u16 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->u16 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->u16 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->i32 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->i32 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->i32 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->i32 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->i32 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->i32 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->i32 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->i32 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->i32 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->i32 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->i32 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->u32 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->u32 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->u32 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->u32 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->u32 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->u32 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->u32 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->u32 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->u32 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->u32 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->u32 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->i64 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->i64 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->i64 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->i64 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->i64 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->i64 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->i64 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->i64 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->i64 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->i64 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->i64 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->u64 = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->u64 = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->u64 = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->u64 = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->u64 = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->u64 = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->u64 = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->u64 = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->u64 = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->u64 = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->u64 = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->fval = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->fval = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->fval = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->fval = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->fval = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->fval = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->fval = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->fval = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->fval = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->fval = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->fval = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->dval = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->dval = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->dval = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->dval = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->dval = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->dval = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->dval = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->dval = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->dval = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->dval = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->dval = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (in_type) {
+               case PSI_T_INT8:
+                       out_val->ldval = in_val->i8;
+                       break;
+               case PSI_T_UINT8:
+                       out_val->ldval = in_val->u8;
+                       break;
+               case PSI_T_INT16:
+                       out_val->ldval = in_val->i16;
+                       break;
+               case PSI_T_UINT16:
+                       out_val->ldval = in_val->u16;
+                       break;
+               case PSI_T_INT32:
+                       out_val->ldval = in_val->i32;
+                       break;
+               case PSI_T_UINT32:
+                       out_val->ldval = in_val->u32;
+                       break;
+               case PSI_T_INT64:
+                       out_val->ldval = in_val->i64;
+                       break;
+               case PSI_T_UINT64:
+                       out_val->ldval = in_val->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       out_val->ldval = in_val->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       out_val->ldval = in_val->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       out_val->ldval = in_val->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+}
+
diff --git a/src/calc/cmp.h b/src/calc/cmp.h
new file mode 100644 (file)
index 0000000..8fac2f3
--- /dev/null
@@ -0,0 +1,2945 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include <assert.h>
+
+#include "token.h"
+
+static inline token_t psi_calc_cmp_eq(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i8 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i8 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i8 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i8 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i8 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i8 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i8 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i8 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i8 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i8 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i8 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u8 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u8 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u8 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u8 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u8 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u8 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u8 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u8 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u8 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u8 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u8 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i16 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i16 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i16 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i16 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i16 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i16 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i16 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i16 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i16 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i16 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i16 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u16 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u16 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u16 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u16 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u16 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u16 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u16 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u16 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u16 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u16 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u16 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i32 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i32 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i32 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i32 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i32 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i32 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i32 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i32 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i32 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i32 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i32 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u32 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u32 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u32 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u32 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u32 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u32 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u32 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u32 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u32 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u32 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u32 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i64 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i64 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i64 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i64 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i64 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i64 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i64 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i64 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i64 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i64 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i64 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u64 == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u64 == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u64 == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u64 == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u64 == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u64 == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u64 == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u64 == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u64 == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u64 == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u64 == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->fval == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->fval == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->fval == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->fval == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->fval == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->fval == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->fval == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->fval == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->fval == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->fval == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->fval == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->dval == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->dval == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->dval == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->dval == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->dval == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->dval == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->dval == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->dval == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->dval == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->dval == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->dval == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->ldval == v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->ldval == v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->ldval == v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->ldval == v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->ldval == v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->ldval == v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->ldval == v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->ldval == v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->ldval == v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->ldval == v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->ldval == v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_cmp_ne(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i8 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i8 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i8 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i8 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i8 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i8 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i8 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i8 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i8 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i8 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i8 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u8 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u8 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u8 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u8 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u8 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u8 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u8 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u8 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u8 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u8 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u8 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i16 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i16 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i16 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i16 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i16 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i16 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i16 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i16 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i16 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i16 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i16 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u16 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u16 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u16 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u16 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u16 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u16 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u16 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u16 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u16 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u16 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u16 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i32 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i32 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i32 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i32 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i32 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i32 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i32 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i32 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i32 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i32 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i32 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u32 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u32 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u32 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u32 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u32 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u32 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u32 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u32 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u32 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u32 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u32 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i64 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i64 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i64 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i64 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i64 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i64 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i64 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i64 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i64 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i64 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i64 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u64 != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u64 != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u64 != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u64 != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u64 != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u64 != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u64 != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u64 != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u64 != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u64 != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u64 != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->fval != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->fval != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->fval != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->fval != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->fval != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->fval != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->fval != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->fval != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->fval != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->fval != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->fval != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->dval != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->dval != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->dval != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->dval != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->dval != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->dval != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->dval != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->dval != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->dval != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->dval != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->dval != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->ldval != v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->ldval != v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->ldval != v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->ldval != v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->ldval != v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->ldval != v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->ldval != v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->ldval != v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->ldval != v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->ldval != v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->ldval != v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_cmp_lt(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i8 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i8 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i8 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i8 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i8 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i8 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i8 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i8 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i8 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i8 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i8 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u8 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u8 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u8 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u8 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u8 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u8 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u8 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u8 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u8 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u8 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u8 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i16 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i16 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i16 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i16 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i16 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i16 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i16 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i16 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i16 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i16 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i16 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u16 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u16 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u16 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u16 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u16 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u16 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u16 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u16 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u16 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u16 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u16 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i32 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i32 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i32 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i32 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i32 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i32 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i32 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i32 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i32 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i32 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i32 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u32 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u32 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u32 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u32 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u32 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u32 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u32 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u32 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u32 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u32 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u32 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i64 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i64 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i64 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i64 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i64 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i64 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i64 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i64 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i64 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i64 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i64 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT64:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u64 < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u64 < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u64 < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u64 < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u64 < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u64 < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u64 < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u64 < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u64 < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u64 < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u64 < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_FLOAT:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->fval < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->fval < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->fval < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->fval < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->fval < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->fval < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->fval < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->fval < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->fval < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->fval < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->fval < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->dval < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->dval < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->dval < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->dval < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->dval < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->dval < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->dval < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->dval < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->dval < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->dval < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->dval < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->ldval < v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->ldval < v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->ldval < v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->ldval < v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->ldval < v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->ldval < v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->ldval < v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->ldval < v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->ldval < v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->ldval < v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->ldval < v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+#endif
+
+       default:
+               assert(0);
+               break;
+       }
+       return PSI_T_UINT8;
+}
+
+static inline token_t psi_calc_cmp_gt(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       switch (t1) {
+       case PSI_T_INT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i8 > v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i8 > v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i8 > v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i8 > v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i8 > v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i8 > v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i8 > v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i8 > v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i8 > v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i8 > v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i8 > v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT8:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u8 > v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u8 > v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u8 > v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u8 > v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u8 > v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u8 > v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u8 > v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u8 > v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u8 > v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u8 > v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u8 > v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i16 > v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i16 > v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i16 > v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i16 > v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i16 > v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i16 > v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i16 > v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i16 > v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i16 > v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i16 > v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->i16 > v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_UINT16:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->u16 > v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->u16 > v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->u16 > v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->u16 > v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->u16 > v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->u16 > v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->u16 > v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->u16 > v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->u16 > v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->u16 > v2->dval;
+                       break;
+#      if HAVE_LONG_DOUBLE
+               case PSI_T_LONG_DOUBLE:
+                       res->u8 = v1->u16 > v2->ldval;
+                       break;
+#      endif
+
+               default:
+                       assert(0);
+                       break;
+               }
+               break;
+       case PSI_T_INT32:
+               switch (t2) {
+               case PSI_T_INT8:
+                       res->u8 = v1->i32 > v2->i8;
+                       break;
+               case PSI_T_UINT8:
+                       res->u8 = v1->i32 > v2->u8;
+                       break;
+               case PSI_T_INT16:
+                       res->u8 = v1->i32 > v2->i16;
+                       break;
+               case PSI_T_UINT16:
+                       res->u8 = v1->i32 > v2->u16;
+                       break;
+               case PSI_T_INT32:
+                       res->u8 = v1->i32 > v2->i32;
+                       break;
+               case PSI_T_UINT32:
+                       res->u8 = v1->i32 > v2->u32;
+                       break;
+               case PSI_T_INT64:
+                       res->u8 = v1->i32 > v2->i64;
+                       break;
+               case PSI_T_UINT64:
+                       res->u8 = v1->i32 > v2->u64;
+                       break;
+               case PSI_T_FLOAT:
+                       res->u8 = v1->i32 > v2->fval;
+                       break;
+               case PSI_T_DOUBLE:
+                       res->u8 = v1->i32 > v2->dval;