// FOR who IN what WHERE where DO how static bool iterate(struct context *context, enum Opcode op, struct program_state *state, struct byte_array *program) { struct byte_array *who = serial_decode_string(program); struct byte_array *where = serial_decode_string(program); struct byte_array *how = serial_decode_string(program); #ifdef DEBUG DEBUGPRINT("%s %s\n", NUM_TO_STRING(opcodes, op), byte_array_to_string(who)); if (!context->runtime) { if (where && where->length) { DEBUGPRINT("%s\tWHERE\n", indentation(context)); display_code(context, where); } DEBUGPRINT("%s\tDO\n", indentation(context)); display_code(context, how); return false; } #endif bool comprehending = (op == VM_COM); struct variable *result = comprehending ? variable_new_list(context, NULL) : NULL; struct variable *what = variable_pop(context); uint32_t len = variable_length(context, what); for (int i=0; i<len; i++) { struct variable *that = list_get_int(context, what, i); set_named_variable(context, state, who, that); byte_array_reset(where); byte_array_reset(how); if (where && where->length) run(context, where, NULL, true); if (!where || !where->length || test_operand(context)) { if (run(context, how, NULL, true)) // true if run hit VM_RET return true; if (comprehending) { struct variable *item = (struct variable*)stack_pop(context->operand_stack); array_add(result->list, item); } } } if (comprehending) stack_push(context->operand_stack, result); return false; }
int compar(struct context *context, const void *a, const void *b, struct variable *comparator) { struct variable *av = *(struct variable**)a; struct variable *bv = *(struct variable**)b; if (comparator) { byte_array_reset(comparator->str); vm_call(context, comparator, av, bv, NULL); struct variable *result = (struct variable*)stack_pop(context->operand_stack); if (result->type == VAR_SRC) result = array_get(result->list.ordered, 0); assert_message(result->type == VAR_INT, "non-integer comparison result"); return result->integer; } else { enum VarType at = av->type; enum VarType bt = bv->type; if (at == VAR_INT && bt == VAR_INT) { // DEBUGPRINT("compare %p:%d to %p:%d : %d\n", av, av->integer, bv, bv->integer, av->integer - bv->integer); return av->integer - bv->integer; } else DEBUGPRINT("can't compare %s to %s\n", var_type_str(at), var_type_str(bt)); vm_exit_message(context, "incompatible types for comparison"); return 0; } }
static inline struct variable *cfnc_serialize(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *indexable = (struct variable*)array_get(args->list.ordered, 0); struct byte_array *bits = variable_serialize(context, NULL, indexable); byte_array_reset(bits); struct variable *result = variable_new_str(context, bits); byte_array_del(bits); return result; }
void display_program(struct byte_array *program) { struct context *context = context_new(false); INDENT DEBUGPRINT("%sprogram bytes:\n", indentation(context)); INDENT for (int i=0; i<program->length; i++) DEBUGPRINT("%s%2d:%3d\n", indentation(context), i, program->data[i]); UNDENT DEBUGPRINT("%sprogram instructions:\n", indentation(context)); byte_array_reset(program); display_code(context, program); UNDENT UNDENT }
void execute(struct byte_array *program, find_c_var *find) { #ifdef DEBUG display_program(program); #endif DEBUGPRINT("execute:\n"); null_check(program); program = byte_array_copy(program); byte_array_reset(program); struct context *context = context_new(false); context->find = find; #ifdef DEBUG context->indent = 1; #endif if (!setjmp(trying)) run(context, program, NULL, false); assert_message(stack_empty(context->operand_stack), "operand stack not empty"); }