diff --git a/c/compile.c b/c/compile.c index d2b9cee7..93f71888 100644 --- a/c/compile.c +++ b/c/compile.c @@ -288,6 +288,25 @@ block gen_collect(block expr) { return c; } +block gen_assign(block expr) { + block c = gen_noop(); + block_append(&c, gen_op_simple(DUP)); + block result_var = block_bind(gen_op_var_unbound(STOREV, "result"), + gen_noop(), OP_HAS_VARIABLE); + block_append(&c, result_var); + + block loop = gen_noop(); + block_append(&loop, gen_op_simple(DUP)); + block_append(&loop, expr); + block_append(&loop, gen_op_var_bound(ASSIGN, result_var)); + block_append(&loop, gen_op_simple(BACKTRACK)); + + block_append(&c, gen_op_target(FORK, loop)); + block_append(&c, loop); + block_append(&c, gen_op_var_bound(LOADV, result_var)); + return c; +} + block gen_else(block a, block b) { assert(0); } diff --git a/c/compile.h b/c/compile.h index d72ddcef..2ce02c0e 100644 --- a/c/compile.h +++ b/c/compile.h @@ -25,6 +25,7 @@ block gen_op_symbol(opcode op, const char* name); block gen_subexp(block a); block gen_both(block a, block b); block gen_collect(block expr); +block gen_assign(block expr); block gen_else(block a, block b); diff --git a/c/execute.c b/c/execute.c index 9d952d6b..f9e2570c 100644 --- a/c/execute.c +++ b/c/execute.c @@ -12,6 +12,8 @@ #include "forkable_stack.h" #include "frame_layout.h" +#include "jv.h" + typedef struct { json_t* value; @@ -108,6 +110,8 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin return *frame_closure_arg(fr, idx); } } + + #define stack_push stk_push #define stack_pop stk_pop @@ -245,20 +249,37 @@ json_t* jq_next() { } #endif + case ASSIGN_DBG: { + stackval replacement = stack_pop(); + stackval path_end = stack_pop(); + stackval path_start = stack_pop(); + json_t* obj = jv_insert(path_start.value, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + stack_push(stackval_replace(path_start, obj)); + break; + } + + case ASSIGN: { + stackval replacement = stack_pop(); + stackval path_end = stack_pop(); + stackval path_start = stack_pop(); + + uint16_t level = *pc++; + uint16_t v = *pc++; + frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); + json_t** var = frame_local_var(fp, v); + *var = jv_insert(*var, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + break; + } + case INDEX: { stackval t = stack_pop(); json_t* k = stack_pop().value; - stackval v; - if (json_is_string(k)) { - v.value = json_object_get(t.value, json_string_value(k)); - } else if (json_is_integer(k)) { - v.value = json_array_get(t.value, json_integer_value(k)); - } else { - assert(0 && "key neither string nor int"); - } - if (v.value) { - v.pathidx = path_push(t, k); - stack_push(v); + json_t* v = jv_lookup(t.value, k); + if (v) { + stackval sv; + sv.value = v; + sv.pathidx = path_push(t, k); + stack_push(sv); } else { assert(0 && "bad lookup"); } @@ -314,6 +335,7 @@ json_t* jq_next() { pc++; // skip offset this time break; } + case ON_BACKTRACK(FORK): { uint16_t offset = *pc++; pc += offset; diff --git a/c/jv.h b/c/jv.h new file mode 100644 index 00000000..fc964fa9 --- /dev/null +++ b/c/jv.h @@ -0,0 +1,41 @@ +#ifndef JV_H +#define JV_H + +#include + +static json_t* jv_lookup(json_t* t, json_t* k) { + json_t* v; + if (json_is_object(t) && json_is_string(k)) { + v = json_object_get(t, json_string_value(k)); + } else if (json_is_array(t) && json_is_number(k)) { + v = json_array_get(t, json_integer_value(k)); + } else { + assert(0&&"bad lookup"); + } + if (v) + return v; + else + return json_null(); +} + +static json_t* jv_modify(json_t* t, json_t* k, json_t* v) { + t = json_copy(t); + if (json_is_object(t) && json_is_string(k)) { + json_object_set(t, json_string_value(k), v); + } else if (json_is_array(t) && json_is_number(k)) { + json_array_set(t, json_integer_value(k), v); + } else { + assert(0 && "bad mod"); + } + return t; +} + +static json_t* jv_insert(json_t* root, json_t* value, json_t** path, int pathlen) { + if (pathlen == 0) { + return value; + } + return jv_modify(root, *path, jv_insert(jv_lookup(root, *path), value, path+1, pathlen-1)); +} + + +#endif diff --git a/c/lexer.l b/c/lexer.l index abf33263..e4ffafce 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -12,6 +12,7 @@ "==" { return EQ; } "as" { return AS; } "def" { return DEF; } +"|=" { return SETPIPE; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} [[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} diff --git a/c/opcode_list.h b/c/opcode_list.h index 1d6d2773..dde07226 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -14,6 +14,9 @@ OP(BACKTRACK, NONE, 0, 0) OP(APPEND, NONE, 2, 1) OP(INSERT, NONE, 4, 2) +OP(ASSIGN_DBG, NONE, 3, 1) +OP(ASSIGN, VARIABLE, 3, 0) + OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) diff --git a/c/parser.y b/c/parser.y index ebc90a32..31c70865 100644 --- a/c/parser.y +++ b/c/parser.y @@ -28,6 +28,8 @@ %token EQ "==" %token AS "as" %token DEF "def" +%token SETPIPE "|=" +%nonassoc '=' SETPIPE %nonassoc EQ %left '+' @@ -76,6 +78,22 @@ Term "as" '$' IDENT '|' Exp { block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6, OP_HAS_VARIABLE)); } | +Exp '=' Exp { + block assign = gen_op_simple(DUP); + block_append(&assign, $3); + block_append(&assign, gen_op_simple(SWAP)); + block_append(&assign, $1); + block_append(&assign, gen_op_simple(SWAP)); + $$ = gen_assign(assign); +} | + +Exp "|=" Exp { + block assign = $1; + block_append(&assign, gen_op_simple(DUP)); + block_append(&assign, $3); + $$ = gen_assign(assign); +} | + Exp '|' Exp { $$ = block_join($1, $3); } | diff --git a/c/testdata b/c/testdata index f2bd4ee3..1d8420d6 100644 --- a/c/testdata +++ b/c/testdata @@ -153,3 +153,4 @@ def f(x): $$x | $$x; $$f([.], . + [42]) [[1,2,3],42] [[1,2,3,42]] [1,2,3,42,42] +