static void push_fnc(struct context *context, struct byte_array *program) { uint32_t num_closures = serial_decode_int(program); struct map *closures = NULL; for (int i=0; i<num_closures; i++) { struct byte_array *name = serial_decode_string(program); if (context->runtime) { if (!closures) closures = map_new(); struct variable *c = find_var(context, name); c = variable_copy(context, c); map_insert(closures, name, c); } } struct byte_array *body = serial_decode_string(program); DEBUGPRINT("FNC %u,%u\n", num_closures, body->length); //display_code(context, body); if (context->runtime) { struct variable *f = variable_new_fnc(context, body, closures); variable_push(context, f); } }
void *incoming_connection(void *arg) { char readline[MAXLINE]; struct thread_argument *ta = (struct thread_argument *)arg; struct context *context = context_new(true, true); context->find = ta->find; for (;;) { bzero(readline, sizeof(readline)); int n; if (((n = CyaSSL_read(ta->ssl, readline, MAXLINE)) <= 0)) { fprintf(stderr, "client closed connection\n"); goto free_ssl; } fprintf(stderr, "%d bytes received: %s\n", n, readline); struct byte_array *raw_message = byte_array_new_size(n); raw_message->data = (uint8_t*)readline; int32_t raw_message_length = serial_decode_int(raw_message); assert_message(raw_message_length < MAXLINE, "todo: handle long messages"); struct variable *message = variable_deserialize(context, raw_message); struct variable *listener = (struct variable *)map_get(server_listeners, (void*)(VOID_INT)ta->fd); vm_call(context, listener, message); } free_ssl: CyaSSL_free(ta->ssl); // Free CYASSL object free(ta); context_del(context); return NULL; }
static void push_bool(struct context *context, struct byte_array *program) { null_check(program); int32_t num = serial_decode_int(program); VM_DEBUGPRINT("BOOL %d\n", num); struct variable* var = variable_new_bool(context, num); variable_push(context, var); }
void serial_decode(struct byte_array* buf, serial_element se, const void* extra) { while (buf->current < buf->data + buf->length) { // get key and wire type int32_t keyWire = serial_decode_int(buf); struct key_value_pair pair = { .key = keyWire >> 2, .wire_type = (enum serial_type)(keyWire & 0x03) }; // get data switch(pair.wire_type) { case SERIAL_INT: /* int */ pair.value.integer = serial_decode_int(buf); break; case SERIAL_FLOAT: pair.value.floater = serial_decode_float(buf); case SERIAL_STRING: /* bytes */ pair.value.bytes = serial_decode_string(buf); break; case SERIAL_ARRAY: break; default: DEBUGPRINT("serial_decode ?\n"); break; } if (se(&pair, buf, extra)) { // DEBUGPRINT("serial_decode: break\n"); break; } } // DEBUGPRINT("serial_decode done\n"); } // assume little endian struct byte_array *encode_float(struct byte_array *buf, float f) { assert_message(sizeof(float)==4, "bad float size"); uint8_t *uf = (uint8_t*)&f; for (int i=4; i; i--) { byte_array_add_byte(buf, *uf); uf++; } return buf; }
static int32_t iff(struct context *context, struct byte_array *program) { null_check(program); int32_t offset = serial_decode_int(program); DEBUGPRINT("IF %d\n", offset); if (!context->runtime) return 0; return test_operand(context) ? 0 : (VOID_INT)offset; }
struct variable *src(struct context *context, enum Opcode op, struct byte_array *program) { int32_t size = serial_decode_int(program); DEBUGPRINT("%s %d\n", NUM_TO_STRING(opcodes, op), size); if (!context->runtime) return NULL; struct variable *v = variable_new_src(context, size); stack_push(context->operand_stack, v); return v; }
struct byte_array* serial_decode_string(struct byte_array* buf) { null_check(buf); int32_t len = serial_decode_int(buf); assert_message(len>=0, "negative malloc"); struct byte_array* ba = byte_array_new_size(len); ba->data = ba->current = (uint8_t*)malloc(len); null_check(ba->data); memcpy(ba->data, buf->current, len); buf->current += len; return ba; }
static int32_t jump(struct context *context, struct byte_array *program) { null_check(program); uint8_t *start = program->current; int32_t offset = serial_decode_int(program); DEBUGPRINT("JMP %d\n", offset); if (!context->runtime) return 0; if (offset < 0) // skip over current VM_JMP instruction when going backward offset -= (program->current - start) + 1; return offset;// - (program->current - start); }
static void push_map(struct context *context, struct byte_array *program) { int32_t num_items = serial_decode_int(program); DEBUGPRINT("MAP %d", num_items); if (!context->runtime) VM_DEBUGPRINT("\n"); struct map *map = map_new(); while (num_items--) { struct variable* value = variable_pop(context); struct variable* key = variable_pop(context); assert_message(key->type==VAR_STR, "non-string map index"); map_insert(map, key->str, value); } struct variable *v = variable_new_map(context, map); DEBUGPRINT(": %s\n", variable_value_str(context, v)); variable_push(context, v); }
static int32_t boolean_op(struct context *context, struct byte_array *program, enum Opcode op) { null_check(program); int32_t short_circuit = serial_decode_int(program); DEBUGPRINT("%s %d\n", NUM_TO_STRING(opcodes, op), short_circuit); if (!context->runtime) return 0; struct variable *v = variable_pop(context); null_check(v); bool indeed_quite_so; switch (v->type) { case VAR_BOOL: indeed_quite_so = v->boolean; break; case VAR_FLT: indeed_quite_so = v->floater; break; case VAR_INT: indeed_quite_so = v->integer; break; case VAR_NIL: return 0; default: indeed_quite_so = true; break; } if (indeed_quite_so ^ (op == VM_AND)) { stack_push(context->operand_stack, v); return short_circuit; } return 0; }
static void push_list(struct context *context, struct byte_array *program) { int32_t num_items = serial_decode_int(program); DEBUGPRINT("LST %d", num_items); if (!context->runtime) VM_DEBUGPRINT("\n"); struct array *items = array_new(); struct map *map = NULL; while (num_items--) { struct variable* v = variable_pop(context); if (v->type == VAR_MAP) { if (!map) map = map_new(context, NULL); map_update(map, v->map); // mapped values are stored in the map, not list } else array_insert(items, 0, v); } struct variable *list = variable_new_list(context, items); list->map = map; DEBUGPRINT(": %s\n", variable_value_str(context, list)); variable_push(context, list); }