}
static struct cfunction function_list[] = {
- {f_plus, "_plus", CALL_BUILTIN_3_1},
- {f_minus, "_minus", CALL_BUILTIN_3_1},
- {f_multiply, "_multiply", CALL_BUILTIN_3_1},
- {f_divide, "_divide", CALL_BUILTIN_3_1},
- {f_tonumber, "tonumber", CALL_BUILTIN_1_1},
- {f_tostring, "tostring", CALL_BUILTIN_1_1},
- {f_keys, "keys", CALL_BUILTIN_1_1},
- {f_equal, "_equal", CALL_BUILTIN_3_1},
- {f_notequal, "_notequal", CALL_BUILTIN_3_1},
- {f_less, "_less", CALL_BUILTIN_3_1},
- {f_greater, "_greater", CALL_BUILTIN_3_1},
- {f_lesseq, "_lesseq", CALL_BUILTIN_3_1},
- {f_greatereq, "_greatereq", CALL_BUILTIN_3_1},
- {f_contains, "_contains", CALL_BUILTIN_3_1},
- {f_length, "length", CALL_BUILTIN_1_1},
- {f_type, "type", CALL_BUILTIN_1_1},
- {f_add, "add", CALL_BUILTIN_1_1},
- {f_sort, "sort", CALL_BUILTIN_1_1},
+ {f_plus, "_plus", 3},
+ {f_minus, "_minus", 3},
+ {f_multiply, "_multiply", 3},
+ {f_divide, "_divide", 3},
+ {f_tonumber, "tonumber", 1},
+ {f_tostring, "tostring", 1},
+ {f_keys, "keys", 1},
+ {f_equal, "_equal", 3},
+ {f_notequal, "_notequal", 3},
+ {f_less, "_less", 3},
+ {f_greater, "_greater", 3},
+ {f_lesseq, "_lesseq", 3},
+ {f_greatereq, "_greatereq", 3},
+ {f_contains, "_contains", 3},
+ {f_length, "length", 1},
+ {f_type, "type", 1},
+ {f_add, "add", 1},
+ {f_sort, "sort", 1},
};
static struct symbol_table cbuiltins = {function_list, sizeof(function_list)/sizeof(function_list[0])};
static int bytecode_operation_length(uint16_t* codeptr) {
if (opcode_describe(*codeptr)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
- return 2 + codeptr[1] * 2;
+ return 4 + codeptr[1] * 2;
} else {
return opcode_length(*codeptr);
}
if (op->length > 1) {
uint16_t imm = bc->code[pc++];
if (op->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
- for (int i=0; i<imm; i++) {
+ for (int i=0; i<imm+1; i++) {
uint16_t level = bc->code[pc++];
uint16_t idx = bc->code[pc++];
if (idx & ARG_NEWCLOSURE) {
struct cfunction {
cfunction_ptr fptr;
const char* name;
- opcode callop;
+ int nargs;
};
#define MAX_CFUNCTION_ARGS 10
}
block gen_call(const char* name, block args) {
- inst* i = inst_new(CALL_1_1);
+ inst* i = inst_new(CALL_JQ);
i->arglist = BLOCK(gen_op_block_unbound(CLOSURE_REF, name), args);
return BLOCK(inst_block(i), inst_block(inst_new(CALLSEQ_END)));
}
block ret = gen_noop();
for (inst* curr; (curr = block_take(&b));) {
if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
- assert(curr->op == CALL_1_1);
+ assert(curr->op == CALL_JQ);
inst* seq_end = block_take(&b);
assert(seq_end && seq_end->op == CALLSEQ_END);
// We expand the argument list as a series of instructions
}
assert(!arglist.first);
- curr->imm.intval = nargs;
+ assert(nargs > 0);
+ curr->imm.intval = nargs - 1;
ret = BLOCK(ret, prelude, inst_block(curr), callargs, inst_block(seq_end));
break;
}
// Arguments to C functions not yet supported
inst* cfunction_ref = block_take(&arglist);
block prelude = gen_noop();
- int nargs = 2;
+ int nargs = 1;
for (inst* i; (i = block_take(&arglist)); ) {
assert(i->op == CLOSURE_CREATE); // FIXME
block body = i->subfn;
prelude = BLOCK(prelude, gen_subexp(expand_call_arglist(body)));
nargs++;
}
- assert(curr->op == CALL_1_1);
- curr->op = CALL_BUILTIN_1_1;
+ assert(curr->op == CALL_JQ);
+ curr->op = CALL_BUILTIN;
curr->imm.intval = nargs;
assert(!curr->arglist.first);
curr->arglist = inst_block(cfunction_ref);
const struct opcode_description* op = opcode_describe(curr->op);
if (op->length == 0)
continue;
- uint16_t* opcode_rewrite = &code[pos];
code[pos++] = curr->op;
int opflags = op->flags;
assert(!(op->flags & OP_IS_CALL_PSEUDO));
- if (curr->op == CALL_BUILTIN_1_1) {
+ if (curr->op == CALL_BUILTIN) {
int nargs = curr->imm.intval;
code[pos++] = (uint16_t)nargs;
assert(block_is_single(curr->arglist));
inst* cfunc = curr->arglist.first;
assert(cfunc && cfunc->bound_by->op == CLOSURE_CREATE_C);
- assert(opcode_length(*opcode_rewrite) ==
- opcode_length(bc->globals->cfunctions[cfunc->bound_by->imm.intval].callop));
- *opcode_rewrite = bc->globals->cfunctions[cfunc->bound_by->imm.intval].callop;
+ //*opcode_rewrite = bc->globals->cfunctions[cfunc->bound_by->imm.intval].callop;
code[pos++] = cfunc->bound_by->imm.intval;
// FIXME arg errors
- assert(nargs > 0);
+ assert(nargs == bc->globals->cfunctions[cfunc->bound_by->imm.intval].nargs);
} else if (opflags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
- assert(curr->op == CALL_1_1);
+ assert(curr->op == CALL_JQ);
int nargs = curr->imm.intval;
- assert(nargs > 0 && nargs < 100); //FIXME
+ assert(nargs >= 0 && nargs < 100); //FIXME
code[pos++] = (uint16_t)nargs;
curr = curr->next;
assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO);
code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE;
inst* i = curr->bound_by;
// FIXME arg errors
- assert(nargs - 1 == i->compiled->subfunctions[i->imm.intval]->nclosures);
+ assert(nargs == i->compiled->subfunctions[i->imm.intval]->nclosures);
} else {
code[pos++] = curr->bound_by->imm.intval;
// FIXME arg errors
- assert(nargs == 1);
+ assert(nargs == 0);
}
- for (int i=1; i<nargs; i++) {
+ for (int i=0; i<nargs; i++) {
curr = curr->next;
assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO);
assert(curr->op == CLOSURE_REF);
printf("\t");
const struct opcode_description* opdesc = opcode_describe(opcode);
data_stk_elem* param;
- for (int i=0; i<opdesc->stack_in; i++) {
+ int stack_in = opdesc->stack_in;
+ if (stack_in == -1) stack_in = pc[1];
+ for (int i=0; i<stack_in; i++) {
if (i == 0) {
param = forkable_stack_peek(&data_stk);
} else {
return value;
}
- case CALL_BUILTIN_1_1: {
- assert(*pc == 2);
- pc++; // skip nclosures
+ case CALL_BUILTIN: {
+ int nargs = *pc++;
stackval top = stack_pop();
cfunc_input[0] = top.value;
- struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++];
- func->fptr(cfunc_input, cfunc_output);
- top.value = cfunc_output[0];
- if (jv_is_valid(top.value)) {
- stack_push(top);
- } else {
- print_error(top.value);
- goto do_backtrack;
+ for (int i = 1; i < nargs; i++) {
+ cfunc_input[i] = stack_pop().value;
}
- break;
- }
-
- case CALL_BUILTIN_3_1: {
- assert(*pc == 4); // no closure args allowed
- pc++; // skip nclosures
- stackval top = stack_pop();
- jv a = stack_pop().value;
- jv b = stack_pop().value;
- cfunc_input[0] = top.value;
- cfunc_input[1] = a;
- cfunc_input[2] = b;
struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++];
func->fptr(cfunc_input, cfunc_output);
top.value = cfunc_output[0];
break;
}
- case CALL_1_1: {
+ case CALL_JQ: {
uint16_t nclosures = *pc++;
+ uint16_t* retaddr = pc + 2 + nclosures*2;
frame_ptr new_frame = frame_push(&frame_stk,
make_closure(&frame_stk, frame_current(&frame_stk), pc),
- pc + nclosures * 2);
+ retaddr);
pc += 2;
frame_ptr old_frame = forkable_stack_peek_next(&frame_stk, new_frame);
- assert(nclosures - 1 == frame_self(new_frame)->bc->nclosures);
- for (int i=0; i<nclosures-1; i++) {
+ assert(nclosures == frame_self(new_frame)->bc->nclosures);
+ for (int i=0; i<nclosures; i++) {
*frame_closure_arg(new_frame, i) = make_closure(&frame_stk, old_frame, pc);
pc += 2;
}
OP(ASSIGN, VARIABLE, 3, 0)
-OP(CALL_BUILTIN_1_1, CFUNC, 1, 1)
-OP(WTFBROKEN, CFUNC, 2, 1)
-OP(CALL_BUILTIN_3_1, CFUNC, 3, 1)
+OP(CALL_BUILTIN, CFUNC, -1, 1)
-OP(CALL_1_1, UFUNC, 1, 1)
+OP(CALL_JQ, UFUNC, 1, 1)
OP(RET, NONE, 1, 1)
OP(CALLSEQ_END, CALLSEQ_END_IMM, 0, 0)