Implement range/3 in C for consistent error handling (#3267)

This commit is contained in:
itchyny authored and GitHub committed 2026-09-18 22:20:58 +09:00
1 parent dd409de28d
commit e371bfaa92
4 files changed
+43 -24

No files matched your search

+10 -12
View File
@@ -2117,21 +2117,19 @@ static block bind_bytecoded_builtins(block b) {
} }
} }
{ {
// Note that we can now define `range` as a jq-coded function
block rangevar = gen_op_var_fresh(STOREV, "rangevar"); block rangevar = gen_op_var_fresh(STOREV, "rangevar");
block rangestart = gen_op_var_fresh(STOREV, "rangestart"); builtins = BLOCK(builtins,
block range = BLOCK(gen_op_simple(DUP), gen_function("range",
gen_call("start", gen_noop()), BLOCK(gen_param_regular("start"),
rangestart, gen_param_regular("end"),
gen_call("end", gen_noop()), gen_param_regular("step")),
BLOCK(gen_op_unbound(LOADV, "step"),
gen_op_simple(DUP), gen_op_simple(DUP),
gen_op_bound(LOADV, rangestart), gen_op_unbound(LOADV, "end"),
// Reset rangevar for every value generated by "end" gen_op_simple(DUP),
gen_op_unbound(LOADV, "start"),
rangevar, rangevar,
gen_op_bound(RANGE, rangevar)); gen_op_bound(RANGE, rangevar))));
builtins = BLOCK(builtins, gen_function("range",
BLOCK(gen_param("start"), gen_param("end")),
range));
} }
return BLOCK(builtins, b); return BLOCK(builtins, b);
} }
+2 -6
View File
@@ -42,7 +42,7 @@ def to_entries: [keys_unsorted[] as $k | {key: $k, value: .[$k]}];
def from_entries: map({ (.key // .Key // .name // .Name): def from_entries: map({ (.key // .Key // .name // .Name):
if has("value") then .value else .Value end }) | add // {}; if has("value") then .value else .Value end }) | add // {};
def with_entries(f): to_entries | map(f) | from_entries; def with_entries(f): to_entries | map(f) | from_entries;
def reverse: [.[length - 1 - range(0;length)]]; def reverse: [.[range(length-1;-1;-1)]];
def indices($i): if type == "array" and ($i|type) == "array" then .[$i] def indices($i): if type == "array" and ($i|type) == "array" then .[$i]
elif type == "array" then .[[$i]] elif type == "array" then .[[$i]]
elif type == "string" and ($i|type) == "string" then _strindices($i) elif type == "string" and ($i|type) == "string" then _strindices($i)
@@ -70,6 +70,7 @@ def join($x): reduce .[] as $i (null;
def _flatten($x): reduce .[] as $i ([]; if $i | type == "array" and $x != 0 then . + ($i | _flatten($x-1)) else . + [$i] end); def _flatten($x): reduce .[] as $i ([]; if $i | type == "array" and $x != 0 then . + ($i | _flatten($x-1)) else . + [$i] end);
def flatten($x): if $x < 0 then error("flatten depth must not be negative") else _flatten($x) end; def flatten($x): if $x < 0 then error("flatten depth must not be negative") else _flatten($x) end;
def flatten: _flatten(-1); def flatten: _flatten(-1);
def range($x;$y): range($x;$y;1);
def range($x): range(0;$x); def range($x): range(0;$x);
def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime; def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ"); def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
@@ -148,11 +149,6 @@ def skip($n; expr):
if $n > 0 then foreach expr as $item ($n; . - 1; if . < 0 then $item else empty end) if $n > 0 then foreach expr as $item ($n; . - 1; if . < 0 then $item else empty end)
elif $n == 0 then expr elif $n == 0 then expr
else error("skip doesn't support negative count") end; else error("skip doesn't support negative count") end;
# range/3, with a `by` expression argument
def range($init; $upto; $by):
if $by > 0 then $init|while(. < $upto; . + $by)
elif $by < 0 then $init|while(. > $upto; . + $by)
else empty end;
def first(g): label $out | g | ., break $out; def first(g): label $out | g | ., break $out;
def isempty(g): first((g|false), true); def isempty(g): first((g|false), true);
def all(generator; condition): isempty(generator|condition and empty); def all(generator; condition): isempty(generator|condition and empty);
+11 -6
View File
@@ -516,24 +516,29 @@ jv jq_next(jq_state *jq) {
uint16_t v = *pc++; uint16_t v = *pc++;
jv* var = frame_local_var(jq, v, level); jv* var = frame_local_var(jq, v, level);
jv max = stack_pop(jq); jv max = stack_pop(jq);
jv step = stack_pop(jq);
if (raising) { if (raising) {
jv_free(max); jv_free(max);
jv_free(step);
goto do_backtrack; goto do_backtrack;
} }
if (jv_get_kind(*var) != JV_KIND_NUMBER ||
jv_get_kind(max) != JV_KIND_NUMBER) { if (jv_get_kind(*var) != JV_KIND_NUMBER || jv_get_kind(max) != JV_KIND_NUMBER ||
set_error(jq, jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric"))); jv_get_kind(step) != JV_KIND_NUMBER) {
set_error(jq, jv_invalid_with_msg(jv_string("Range bounds and step must be numeric")));
jv_free(max); jv_free(max);
jv_free(step);
goto do_backtrack; goto do_backtrack;
} else if (jv_number_value(*var) >= jv_number_value(max)) { } else if (jv_cmp(jv_copy(*var), jv_copy(max)) * jv_cmp(jv_copy(step), jv_number(0)) >= 0) {
/* finished iterating */
jv_free(max); jv_free(max);
jv_free(step);
goto do_backtrack; goto do_backtrack;
} else { } else {
jv curr = *var; jv curr = *var;
*var = jv_number(jv_number_value(*var) + 1); *var = jv_number(jv_number_value(curr) + jv_number_value(step));
struct stack_pos spos = stack_get_pos(jq); struct stack_pos spos = stack_get_pos(jq);
stack_push(jq, step);
stack_push(jq, max); stack_push(jq, max);
stack_save(jq, pc - 3, spos); stack_save(jq, pc - 3, spos);
+20
View File
@@ -304,10 +304,30 @@ null
null null
[0,-1,-2,-3,-4] [0,-1,-2,-3,-4]
[range(0;-10;-3)]
null
[0,-3,-6,-9]
[range(0;10;0)]
null
[]
[range(0,1;4,5;1,2)] [range(0,1;4,5;1,2)]
null null
[0,1,2,3,0,2, 0,1,2,3,4,0,2,4, 1,2,3,1,3, 1,2,3,4,1,3] [0,1,2,3,0,2, 0,1,2,3,4,0,2,4, 1,2,3,1,3, 1,2,3,4,1,3]
try range(.) catch .
null
"Range bounds and step must be numeric"
try range(0;"") catch .
null
"Range bounds and step must be numeric"
try range(0;1;[]) catch .
null
"Range bounds and step must be numeric"
[while(.<100; .*2)] [while(.<100; .*2)]
1 1
[1,2,4,8,16,32,64] [1,2,4,8,16,32,64]