mirror of
https://github.com/stedolan/jq.git
synced 2024-05-11 05:55:39 +00:00
Fold constants (fix #504)
This commit is contained in:
20
compile.c
20
compile.c
@@ -97,7 +97,7 @@ static block inst_block(inst* i) {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int block_is_single(block b) {
|
int block_is_single(block b) {
|
||||||
return b.first && b.first == b.last;
|
return b.first && b.first == b.last;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +131,10 @@ block gen_noop() {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int block_is_noop(block b) {
|
||||||
|
return (b.first == 0 && b.last == 0);
|
||||||
|
}
|
||||||
|
|
||||||
block gen_op_simple(opcode op) {
|
block gen_op_simple(opcode op) {
|
||||||
assert(opcode_describe(op)->length == 1);
|
assert(opcode_describe(op)->length == 1);
|
||||||
return inst_block(inst_new(op));
|
return inst_block(inst_new(op));
|
||||||
@@ -144,6 +148,20 @@ block gen_const(jv constant) {
|
|||||||
return inst_block(i);
|
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) {
|
block gen_op_target(opcode op, block target) {
|
||||||
assert(opcode_describe(op)->flags & OP_HAS_BRANCH);
|
assert(opcode_describe(op)->flags & OP_HAS_BRANCH);
|
||||||
assert(target.last);
|
assert(target.last);
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ typedef struct block {
|
|||||||
block gen_location(location, struct locfile*, block);
|
block gen_location(location, struct locfile*, block);
|
||||||
|
|
||||||
block gen_noop();
|
block gen_noop();
|
||||||
|
int block_is_noop(block b);
|
||||||
block gen_op_simple(opcode op);
|
block gen_op_simple(opcode op);
|
||||||
block gen_const(jv constant);
|
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_target(opcode op, block target);
|
||||||
block gen_op_unbound(opcode op, const char* name);
|
block gen_op_unbound(opcode op, const char* name);
|
||||||
block gen_op_bound(opcode op, block binder);
|
block gen_op_bound(opcode op, block binder);
|
||||||
@@ -52,6 +56,7 @@ int block_has_only_binders_and_imports(block, int bindflags);
|
|||||||
int block_has_only_binders(block, int bindflags);
|
int block_has_only_binders(block, int bindflags);
|
||||||
int block_has_main(block);
|
int block_has_main(block);
|
||||||
int block_is_funcdef(block b);
|
int block_is_funcdef(block b);
|
||||||
|
int block_is_single(block b);
|
||||||
block block_bind(block binder, block body, int bindflags);
|
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_library(block binder, block body, int bindflags, const char* libname);
|
||||||
block block_bind_referenced(block binder, block body, int bindflags);
|
block block_bind_referenced(block binder, block body, int bindflags);
|
||||||
|
|||||||
43
parser.y
43
parser.y
@@ -162,7 +162,50 @@ static block gen_slice_index(block obj, block start, block end, opcode idx_op) {
|
|||||||
return BLOCK(key, obj, gen_op_simple(idx_op));
|
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) {
|
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;
|
const char* funcname = 0;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case '+': funcname = "_plus"; break;
|
case '+': funcname = "_plus"; break;
|
||||||
|
|||||||
53
tests/run
53
tests/run
@@ -20,6 +20,59 @@ if [ -z "$d" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
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
|
cat > "$d/.jq" <<EOF
|
||||||
def foo: "baz";
|
def foo: "baz";
|
||||||
def f: "wat";
|
def f: "wat";
|
||||||
|
|||||||
Reference in New Issue
Block a user