#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include "exec_stack.h"
#include "bytecode.h"
#include "jv_alloc.h"
#include "jq_parser.h"
#include "locfile.h"
#include "jv.h"
#include "jq.h"
#include "parser.h"
#include "builtin.h"
#include "util.h"
#include "linker.h"
struct jq_state {
void (*nomem_handler)(void *);
void *nomem_handler_data;
struct bytecode* bc;
jq_err_cb err_cb;
void *err_cb_data;
jv error;
struct stack stk;
stack_ptr curr_frame;
stack_ptr stk_top;
stack_ptr fork_top;
jv path;
int subexp_nest;
int debug_trace_enabled;
int initial_execution;
jv attrs;
};
struct closure {
struct bytecode* bc; // jq bytecode
stack_ptr env; // jq stack address of closed frame
};
// locals for any function called: either a closure or a local variable
union frame_entry {
struct closure closure;
jv localvar;
};
// jq function call frame
struct frame {
struct bytecode* bc; // jq bytecode for callee
stack_ptr env; // jq stack address of frame to return to
stack_ptr retdata; // jq stack address to unwind to on RET
uint16_t* retaddr; // jq bytecode return address
union frame_entry entries[0]; // nclosures + nlocals
};
static int frame_size(struct bytecode* bc) {
return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc->nlocals);
}
static struct frame* frame_current(struct jq_state* jq) {
struct frame* fp = stack_block(&jq->stk, jq->curr_frame);
stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame);
if (next) {
struct frame* fpnext = stack_block(&jq->stk, next);
struct bytecode* bc = fpnext->bc;
assert(fp->retaddr >= bc->code && fp->retaddr < bc->code + bc->codelen);
} else {
assert(fp->retaddr == 0);
}
return fp;
}
static stack_ptr frame_get_level(struct jq_state* jq, int level) {
stack_ptr fr = jq->curr_frame;
for (int i=0; i<level; i++) {
struct frame* fp = stack_block(&jq->stk, fr);
fr = fp->env;
}
return fr;
}
static jv* frame_local_var(struct jq_state* jq, int var, int level) {
struct frame* fr = stack_block(&jq->stk, frame_get_level(jq, level));
assert(var >= 0);
assert(var < fr->bc->nlocals);
return &fr->entries[fr->bc->nclosures + var].localvar;
}
static struct closure make_closure(struct jq_state* jq, uint16_t* pc) {
uint16_t level = *pc++;
uint16_t idx = *pc++;
stack_ptr fridx = frame_get_level(jq, level);
struct frame* fr = stack_block(&jq->stk, fridx);
if (idx & ARG_NEWCLOSURE) {
// A new closure closing the frame identified by level, and with
// the bytecode body of the idx'th subfunction of that frame
int subfn_idx = idx & ~ARG_NEWCLOSURE;
assert(subfn_idx < fr->bc->nsubfunctions);
struct closure cl = {fr->bc->subfunctions[subfn_idx],
fridx};
return cl;
} else {
// A reference to a closure from the frame identified by level; copy
// it as-is
int closure = idx;
assert(closure >= 0);
assert(closure < fr->bc->nclosures);
return fr->entries[closure].closure;
}
}
static