return b;
}
-static int block_is_single(block b) {
+int block_is_single(block b) {
return b.first && b.first == b.last;
}
return b;
}
+int block_is_noop(block b) {
+ return (b.first == 0 && b.last == 0);
+}
+
block gen_op_simple(opcode op) {
assert(opcode_describe(op)->length == 1);
return inst_block(inst_new(op));
return inst_block(i);
}
+int block_is_const(block b) {
+ return (block_is_single(b) && b.first->op == LOADK);
+}
+
+jv_kind block_const_kind(block b) {
+ assert(block_is_const(b));
+ return jv_get_kind(b.first->imm.constant);
+}
+
+jv block_const(block b) {
+ assert(block_is_const(b));
+ return jv_copy(b.first->imm.constant);
+}
+
block gen_op_target(opcode op, block target) {
assert(opcode_describe(op)->flags & OP_HAS_BRANCH);
assert(target.last);
block gen_location(location, struct locfile*, block);
block gen_noop();
+int block_is_noop(block b);
block gen_op_simple(opcode op);
block gen_const(jv constant);
+int block_is_const(block b);
+jv_kind block_const_kind(block b);
+jv block_const(block b);
block gen_op_target(opcode op, block target);
block gen_op_unbound(opcode op, const char* name);
block gen_op_bound(opcode op, block binder);
int block_has_only_binders(block, int bindflags);
int block_has_main(block);
int block_is_funcdef(block b);
+int block_is_single(block b);
block block_bind(block binder, block body, int bindflags);
block block_bind_library(block binder, block body, int bindflags, const char* libname);
block block_bind_referenced(block binder, block body, int bindflags);
return BLOCK(key, obj, gen_op_simple(idx_op));
}
+static block constant_fold(block a, block b, int op) {
+ if (!block_is_single(a) || !block_is_const(a) ||
+ !block_is_single(b) || !block_is_const(b))
+ return gen_noop();
+ if (block_const_kind(a) != block_const_kind(b))
+ return gen_noop();
+
+ jv res = jv_invalid();
+
+ if (block_const_kind(a) == JV_KIND_NUMBER) {
+ double na = jv_number_value(block_const(a));
+ double nb = jv_number_value(block_const(b));
+ switch (op) {
+ case '+': res = jv_number(na + nb); break;
+ case '-': res = jv_number(na - nb); break;
+ case '*': res = jv_number(na * nb); break;
+ case '/': res = jv_number(na / nb); break;
+ case EQ: res = (na == nb ? jv_true() : jv_false()); break;
+ case NEQ: res = (na != nb ? jv_true() : jv_false()); break;
+ case '<': res = (na < nb ? jv_true() : jv_false()); break;
+ case '>': res = (na > nb ? jv_true() : jv_false()); break;
+ case LESSEQ: res = (na <= nb ? jv_true() : jv_false()); break;
+ case GREATEREQ: res = (na >= nb ? jv_true() : jv_false()); break;
+ default: break;
+ }
+ } else if (op == '+' && block_const_kind(a) == JV_KIND_STRING) {
+ res = jv_string_concat(block_const(a), block_const(b));
+ } else {
+ return gen_noop();
+ }
+
+ if (jv_get_kind(res) == JV_KIND_INVALID)
+ return gen_noop();
+
+ block_free(a);
+ block_free(b);
+ return gen_const(res);
+}
+
static block gen_binop(block a, block b, int op) {
+ block folded = constant_fold(a, b, op);
+ if (!block_is_noop(folded))
+ return folded;
+
const char* funcname = 0;
switch (op) {
case '+': funcname = "_plus"; break;
exit 0
fi
+## Test constant folding
+
+# String constant folding (addition only)
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '"foo"' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+
+# Numeric constant folding (not all ops yet)
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '1+1' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '1-1' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '2*3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '9/3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '9==3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '9!=3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '9<=3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+n=`$VALGRIND $Q ./jq -n --debug-dump-disasm '9>=3' | wc -l`
+if [ $n -ne 5 ]; then
+ echo "Constant expression folding for strings didn't work"
+ exit 1
+fi
+
+## Test library/module system
+
cat > "$d/.jq" <<EOF
def foo: "baz";
def f: "wat";