Clean up function creation API and epilogue generation.
This commit is contained in:
1 parent
924aeda504
commit
3e3fe51959
5 files changed
+38
-47
No files matched your search
@@ -252,32 +252,24 @@ static void f_type(jv input[], jv output[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static block j_empty() {
|
static block j_empty() {
|
||||||
return gen_op_block_defn(CLOSURE_CREATE, "empty", gen_op_simple(BACKTRACK));
|
return gen_function("empty", gen_op_simple(BACKTRACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
static block j_false() {
|
static block j_false() {
|
||||||
return gen_op_block_defn(CLOSURE_CREATE, "false",
|
return gen_function("false", gen_op_const(LOADK, jv_false()));
|
||||||
block_join(gen_op_const(LOADK, jv_false()),
|
|
||||||
gen_op_simple(RET)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static block j_true() {
|
static block j_true() {
|
||||||
return gen_op_block_defn(CLOSURE_CREATE, "true",
|
return gen_function("true", gen_op_const(LOADK, jv_true()));
|
||||||
block_join(gen_op_const(LOADK, jv_true()),
|
|
||||||
gen_op_simple(RET)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static block j_null() {
|
static block j_null() {
|
||||||
return gen_op_block_defn(CLOSURE_CREATE, "null",
|
return gen_function("null", gen_op_const(LOADK, jv_null()));
|
||||||
block_join(gen_op_const(LOADK, jv_null()),
|
|
||||||
gen_op_simple(RET)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static block j_not() {
|
static block j_not() {
|
||||||
return gen_op_block_defn(CLOSURE_CREATE, "not",
|
return gen_function("not", gen_condbranch(gen_op_const(LOADK, jv_false()),
|
||||||
block_join(gen_condbranch(gen_op_const(LOADK, jv_false()),
|
gen_op_const(LOADK, jv_true())));
|
||||||
gen_op_const(LOADK, jv_true())),
|
|
||||||
gen_op_simple(RET)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cfunction function_list[] = {
|
static struct cfunction function_list[] = {
|
||||||
|
|||||||
@@ -161,22 +161,6 @@ block gen_op_symbol(opcode op, const char* sym) {
|
|||||||
return inst_block(i);
|
return inst_block(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
block gen_op_block_defn(opcode op, const char* name, block block) {
|
|
||||||
assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
|
|
||||||
assert(opcode_describe(op)->flags & OP_HAS_BLOCK);
|
|
||||||
inst* i = inst_new(op);
|
|
||||||
i->subfn = block;
|
|
||||||
i->symbol = strdup(name);
|
|
||||||
return inst_block(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void block_bind_subblock(block binder, block body, int bindflags);
|
|
||||||
block gen_op_block_defn_rec(opcode op, const char* name, block blk) {
|
|
||||||
block b = gen_op_block_defn(op, name, blk);
|
|
||||||
block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
block gen_op_block_unbound(opcode op, const char* name) {
|
block gen_op_block_unbound(opcode op, const char* name) {
|
||||||
assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
|
assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
|
||||||
inst* i = inst_new(op);
|
inst* i = inst_new(op);
|
||||||
@@ -296,6 +280,16 @@ block block_bind(block binder, block body, int bindflags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
block gen_function(const char* name, block body) {
|
||||||
|
inst* i = inst_new(CLOSURE_CREATE);
|
||||||
|
i->subfn = body;
|
||||||
|
i->symbol = strdup(name);
|
||||||
|
block b = inst_block(i);
|
||||||
|
block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
block gen_subexp(block a) {
|
block gen_subexp(block a) {
|
||||||
return BLOCK(gen_op_simple(DUP), a, gen_op_simple(SWAP));
|
return BLOCK(gen_op_simple(DUP), a, gen_op_simple(SWAP));
|
||||||
}
|
}
|
||||||
@@ -442,11 +436,13 @@ static int count_cfunctions(block b) {
|
|||||||
|
|
||||||
// Expands call instructions into a calling sequence
|
// Expands call instructions into a calling sequence
|
||||||
// Checking for argument count compatibility happens later
|
// Checking for argument count compatibility happens later
|
||||||
static void expand_call_arglist(struct bytecode* bc, block b) {
|
static block expand_call_arglist(struct bytecode* bc, block b) {
|
||||||
for (inst* curr = b.first; curr; curr = curr->next) {
|
block ret = gen_noop();
|
||||||
|
for (inst* curr; (curr = block_take(&b));) {
|
||||||
if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
||||||
assert(curr->op == CALL_1_1);
|
assert(curr->op == CALL_1_1);
|
||||||
assert(curr->next && curr->next->op == CALLSEQ_END);
|
inst* seq_end = block_take(&b);
|
||||||
|
assert(seq_end && seq_end->op == CALLSEQ_END);
|
||||||
// We expand the argument list as a series of instructions
|
// We expand the argument list as a series of instructions
|
||||||
block arglist = curr->arglist;
|
block arglist = curr->arglist;
|
||||||
curr->arglist = gen_noop();
|
curr->arglist = gen_noop();
|
||||||
@@ -478,9 +474,8 @@ static void expand_call_arglist(struct bytecode* bc, block b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(!arglist.first);
|
assert(!arglist.first);
|
||||||
block_insert_before(curr, prelude);
|
|
||||||
block_insert_after(curr, callargs);
|
|
||||||
curr->imm.intval = nargs;
|
curr->imm.intval = nargs;
|
||||||
|
ret = BLOCK(ret, prelude, inst_block(curr), callargs, inst_block(seq_end));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,12 +483,21 @@ static void expand_call_arglist(struct bytecode* bc, block b) {
|
|||||||
// Arguments to C functions not yet supported
|
// Arguments to C functions not yet supported
|
||||||
assert(block_is_single(arglist));
|
assert(block_is_single(arglist));
|
||||||
assert(arglist.first->op == CLOSURE_REF);
|
assert(arglist.first->op == CLOSURE_REF);
|
||||||
block_insert_after(curr, arglist);
|
|
||||||
curr->imm.intval = 1;
|
curr->imm.intval = 1;
|
||||||
|
ret = BLOCK(ret, inst_block(curr), arglist, inst_block(seq_end));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ret = BLOCK(ret, inst_block(curr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bc->parent) {
|
||||||
|
// functions should end in a return
|
||||||
|
return BLOCK(ret, gen_op_simple(RET));
|
||||||
|
} else {
|
||||||
|
// the toplevel should YIELD;BACKTRACK; when it finds an answer
|
||||||
|
return BLOCK(ret, gen_op_simple(YIELD), gen_op_simple(BACKTRACK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
||||||
@@ -502,7 +506,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
|||||||
int var_frame_idx = 0;
|
int var_frame_idx = 0;
|
||||||
bc->nsubfunctions = 0;
|
bc->nsubfunctions = 0;
|
||||||
bc->nclosures = 0;
|
bc->nclosures = 0;
|
||||||
expand_call_arglist(bc, b);
|
b = expand_call_arglist(bc, b);
|
||||||
for (inst* curr = b.first; curr; curr = curr->next) {
|
for (inst* curr = b.first; curr; curr = curr->next) {
|
||||||
if (!curr->next) assert(curr == b.last);
|
if (!curr->next) assert(curr == b.last);
|
||||||
pos += opcode_length(curr->op);
|
pos += opcode_length(curr->op);
|
||||||
|
|||||||
@@ -22,12 +22,11 @@ block gen_op_const(opcode op, jv constant);
|
|||||||
block gen_op_target(opcode op, block target);
|
block gen_op_target(opcode op, block target);
|
||||||
block gen_op_var_unbound(opcode op, const char* name);
|
block gen_op_var_unbound(opcode op, const char* name);
|
||||||
block gen_op_var_bound(opcode op, block binder);
|
block gen_op_var_bound(opcode op, block binder);
|
||||||
block gen_op_block_defn(opcode op, const char* name, block block);
|
|
||||||
block gen_op_block_defn_rec(opcode op, const char* name, block block);
|
|
||||||
block gen_op_block_unbound(opcode op, const char* name);
|
block gen_op_block_unbound(opcode op, const char* name);
|
||||||
block gen_op_call(opcode op, block arglist);
|
block gen_op_call(opcode op, block arglist);
|
||||||
block gen_op_symbol(opcode op, const char* name);
|
block gen_op_symbol(opcode op, const char* name);
|
||||||
|
|
||||||
|
block gen_function(const char* name, block body);
|
||||||
block gen_subexp(block a);
|
block gen_subexp(block a);
|
||||||
block gen_both(block a, block b);
|
block gen_both(block a, block b);
|
||||||
block gen_collect(block expr);
|
block gen_collect(block expr);
|
||||||
|
|||||||
@@ -512,7 +512,6 @@ struct bytecode* jq_compile(const char* str) {
|
|||||||
struct bytecode* bc = 0;
|
struct bytecode* bc = 0;
|
||||||
int nerrors = jq_parse(&locations, &program);
|
int nerrors = jq_parse(&locations, &program);
|
||||||
if (nerrors == 0) {
|
if (nerrors == 0) {
|
||||||
block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
|
|
||||||
program = builtins_bind(program);
|
program = builtins_bind(program);
|
||||||
nerrors = block_compile(program, &locations, &bc);
|
nerrors = block_compile(program, &locations, &bc);
|
||||||
block_free(program);
|
block_free(program);
|
||||||
|
|||||||
@@ -305,14 +305,13 @@ QQSTRING_START QQString QQSTRING_END {
|
|||||||
|
|
||||||
FuncDef:
|
FuncDef:
|
||||||
"def" IDENT ':' Exp ';' {
|
"def" IDENT ':' Exp ';' {
|
||||||
block body = block_join($4, gen_op_simple(RET));
|
$$ = gen_function(jv_string_value($2), $4);
|
||||||
$$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body);
|
|
||||||
jv_free($2);
|
jv_free($2);
|
||||||
} |
|
} |
|
||||||
|
|
||||||
"def" IDENT '(' IDENT ')' ':' Exp ';' {
|
"def" IDENT '(' IDENT ')' ':' Exp ';' {
|
||||||
block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO);
|
block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), $7, OP_IS_CALL_PSEUDO);
|
||||||
$$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body);
|
$$ = gen_function(jv_string_value($2), body);
|
||||||
jv_free($2);
|
jv_free($2);
|
||||||
jv_free($4);
|
jv_free($4);
|
||||||
}
|
}
|
||||||
@@ -393,9 +392,7 @@ IDENT {
|
|||||||
IDENT '(' Exp ')' {
|
IDENT '(' Exp ')' {
|
||||||
$$ = gen_op_call(CALL_1_1,
|
$$ = gen_op_call(CALL_1_1,
|
||||||
block_join(gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)),
|
block_join(gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)),
|
||||||
block_bind(gen_op_block_defn(CLOSURE_CREATE,
|
block_bind(gen_function("@lambda", $3),
|
||||||
"lambda",
|
|
||||||
block_join($3, gen_op_simple(RET))),
|
|
||||||
gen_noop(), OP_IS_CALL_PSEUDO)));
|
gen_noop(), OP_IS_CALL_PSEUDO)));
|
||||||
$$ = gen_location(@1, $$);
|
$$ = gen_location(@1, $$);
|
||||||
jv_free($1);
|
jv_free($1);
|
||||||
|
|||||||
Reference in new issue
Block a user