/* * Return a single tuple containing the contents of the gen'ed tuple chain. */ void gen_flatten(struct value *gen, struct value *dest) { unsigned int dest_size = value_tuple_fetch_integer(gen, GEN_GLOBAL_POS); struct value *current = value_tuple_fetch(gen, GEN_ROOT_TUPLE); unsigned int j = 0; value_tuple_new(dest, value_tuple_get_tag(current), dest_size); while (!value_is_null(current)) { unsigned int i = 0; unsigned int current_size = value_tuple_get_size(current); struct value *x; for (i = 0; i < (current_size - 1) && i < dest_size; i++) { x = value_tuple_fetch(current, i); #ifdef DEBUG process_render(process_err, "(flatten %d/%d -> %d/%d: ", i, current_size, j, dest_size); value_portray(process_err, x); process_render(process_err, ")\n"); #endif value_tuple_store(dest, j, x); j++; } current = value_tuple_fetch(current, (current_size - 1)); } }
static Value _lib_typeof(VMState *vm, Value value) { Hash *args = value_to_ptr(value); Value query_val = hash_find(args, 1); if (value_is_int(query_val)) { return cvm_get_cstring_value(vm, "integer"); } else if (value_is_string(query_val)) { return cvm_get_cstring_value(vm, "string"); } else if (value_is_null(query_val)) { return cvm_get_cstring_value(vm, "null"); } else if (value_is_undefined(query_val)) { return cvm_get_cstring_value(vm, "undefined"); } else { Hash *hash = value_to_ptr(query_val); while (hash->type == HT_REDIRECT) hash = (Hash*)hash->size; assert(hash->type != HT_GC_LEFT); switch (hash->type) { case HT_OBJECT: return cvm_get_cstring_value(vm, "object"); case HT_ARRAY: return cvm_get_cstring_value(vm, "array"); case HT_LIGHTFUNC: return cvm_get_cstring_value(vm, "light_function"); case HT_CLOSURE: return cvm_get_cstring_value(vm, "closure"); case HT_USERDATA: return cvm_get_cstring_value(vm, "userdata"); default: assert(0); return value_undefined(); } } }
/* * Define a label. If the label is already allocated, this will * cause previously-generated forward references to this label to be * backpatched with the now-known location. */ int gen_define_label(struct value *gen, struct value *gen_label) { struct value *tuple = value_tuple_fetch(gen, GEN_CURRENT_TUPLE); unsigned int local_pos = value_tuple_fetch_integer(gen, GEN_LOCAL_POS); unsigned int global_pos = value_tuple_fetch_integer(gen, GEN_GLOBAL_POS); struct value *bp; assert(gen_label != NULL); if (value_is_null(gen_label)) { /* Not yet allocated, so allocate a new undefined one. */ gen_label_new(gen_label); } else { /* Fail if we try to redefine a label. */ if (value_tuple_fetch_integer(gen_label, GEN_LABEL_GLOBAL_POS) != 0) { return 0; } } value_tuple_store(gen_label, GEN_LABEL_TUPLE, tuple); value_tuple_store_integer(gen_label, GEN_LABEL_LOCAL_POS, local_pos); value_tuple_store_integer(gen_label, GEN_LABEL_GLOBAL_POS, global_pos); /* * Resolve any previous forward references by backpatching. */ bp = value_tuple_fetch(gen_label, GEN_LABEL_NEXT); while (!value_is_null(bp)) { /* * Backpatch, by placing the current global position into * the slot named by the bp entry, then remove entry from list. */ value_tuple_store_integer( value_tuple_fetch(bp, GEN_LABEL_TUPLE), value_tuple_fetch_integer(bp, GEN_LABEL_LOCAL_POS), global_pos ); value_tuple_store(gen_label, GEN_LABEL_NEXT, value_tuple_fetch(bp, GEN_LABEL_NEXT)); bp = value_tuple_fetch(gen_label, GEN_LABEL_NEXT); } return 1; }
/* * Generate a reference to a label into the tuple, for instance as the * immediate argument of a branch instruction. If the label parameter * is NULL, this will generate and return a forward reference which * should be resolved by subsequently passing it to gen_define_label(). */ void gen_gen_label_ref(struct value *gen, struct value *gen_label) { struct value *bp; struct value next; int global_pos; assert(gen_label != NULL); if (value_is_null(gen_label)) { /* Not yet allocated, so allocate a new undefined one. */ gen_label_new(gen_label); } global_pos = value_tuple_fetch_integer(gen_label, GEN_LABEL_GLOBAL_POS); if (global_pos != 0) { /* Already defined, so just use it. */ gen_integer(gen, global_pos); return; } /* * The label is newly allocated, or at least has not been defined * yet. So, we remember that we will need to backpatch here in the * future (by adding an entry to the label's backpatch list) and, * for now, generate a NULL in its slot. */ value_copy(&next, value_tuple_fetch(gen_label, GEN_LABEL_NEXT)); bp = value_tuple_fetch(gen_label, GEN_LABEL_NEXT); gen_label_new(bp); value_tuple_store(bp, GEN_LABEL_TUPLE, value_tuple_fetch(gen, GEN_CURRENT_TUPLE)); value_tuple_store(bp, GEN_LABEL_LOCAL_POS, value_tuple_fetch(gen, GEN_LOCAL_POS)); value_tuple_store(bp, GEN_LABEL_GLOBAL_POS, value_tuple_fetch(gen, GEN_GLOBAL_POS)); value_tuple_store(bp, GEN_LABEL_NEXT, &next); gen_value(gen, &VNULL); }
int value_save(struct process *p, struct value *value) { unsigned char squeeze = (unsigned char)value->type; #ifdef DEBUG process_render(process_err, "(save:%s ", type_name_table[(int)squeeze]); if (value->type == VALUE_SYMBOL) { process_render(process_err, "[%d] ", value_symbol_get_length(value)); } value_portray(process_err, value); process_render(process_err, ")\n"); #endif stream_write(NULL, p, &squeeze, sizeof(squeeze)); if ((value->type & VALUE_STRUCTURED) == 0) { stream_write(NULL, p, &value->value, sizeof(value->value)); } else { unsigned int length, i; switch (value->type) { case VALUE_SYMBOL: { const char *token = value_symbol_get_token(value); length = value_symbol_get_length(value); stream_write(NULL, p, &length, sizeof(length)); stream_write(NULL, p, token, sizeof(char) * length); break; } case VALUE_TUPLE: { struct value *tag = value_tuple_get_tag(value); value_save(p, tag); /* XXX should eventually dispatch to a handler based on tag. */ if (value_equal(tag, &tag_dict)) { struct value dict_iter; struct value *key; value_dict_new_iter(&dict_iter, value); length = value_dict_get_layer_size(value); stream_write(NULL, p, &length, sizeof(length)); length = value_dict_get_length(value); stream_write(NULL, p, &length, sizeof(length)); key = value_dict_iter_get_current_key(&dict_iter); while (!value_is_null(key)) { value_save(p, key); value_save(p, value_dict_fetch(value, key)); /* XXX not so good; use iter */ value_dict_iter_advance(&dict_iter); key = value_dict_iter_get_current_key(&dict_iter); } } else { length = value_tuple_get_size(value); stream_write(NULL, p, &length, sizeof(length)); for (i = 0; i < length; i++) { value_save(p, value_tuple_fetch(value, i)); } } break; } default: assert(value->type == VALUE_SYMBOL || value->type == VALUE_TUPLE); break; } } return 1; }