/** * key同士を比較 */ static int mapentry_cmp(Value *vret, Value *v, RefNode *node) { Value v1 = v[0]; Value v2 = v[1]; Value vr; Value_push("vv", Value_ref(v1)->v[INDEX_ENTRY_KEY], Value_ref(v2)->v[INDEX_ENTRY_KEY]); if (!call_member_func(fs->symbol_stock[T_CMP], 1, TRUE)) { return FALSE; } vr = fg->stk_top[-1]; if (Value_isint(vr) && Value_integral(vr) == 0) { Value_pop(); // keyが同じなら、valueを比較 Value_push("vv", Value_ref(v1)->v[INDEX_ENTRY_VAL], Value_ref(v2)->v[INDEX_ENTRY_VAL]); if (!call_member_func(fs->symbol_stock[T_CMP], 1, TRUE)) { return FALSE; } } *vret = fg->stk_top[-1]; fg->stk_top--; return TRUE; }
/** * 検索して見つかった場合/見つからなかった場合は * 1.true/falseを返す * 2.index/nullを返す */ int map_index_of(Value *vret, Value *v, RefNode *node) { RefMap *rm = Value_vp(*v); int ret_index = FUNC_INT(node); Value v1 = v[1]; RefNode *type = Value_type(v1); int i; RefNode *fn_eq = Hash_get_p(&type->u.c.h, fs->symbol_stock[T_EQ]); if (fn_eq == NULL) { throw_error_select(THROW_NO_MEMBER_EXISTS__NODE_REFSTR, type, fs->symbol_stock[T_EQ]); return FALSE; } rm->lock_count++; for (i = 0; i < rm->entry_num; i++) { HashValueEntry *ep = rm->entry[i]; for (; ep != NULL; ep = ep->next) { Value va = ep->val; if (Value_type(va) == type) { if (type == fs->cls_str) { if (refstr_eq(Value_vp(v1), Value_vp(va))) { break; } } else { Value_push("vv", v1, va); if (!call_function(fn_eq, 1)) { goto ERROR_END; } fg->stk_top--; if (Value_bool(*fg->stk_top)) { unref(*fg->stk_top); if (ret_index) { *vret = Value_cp(ep->key); } else { *vret = VALUE_TRUE; } return TRUE; } } } } } if (!ret_index) { *vret = VALUE_FALSE; } rm->lock_count--; return TRUE; ERROR_END: rm->lock_count--; return FALSE; }
/** * 0 : 要素数 * 4 : 要素(key, value, key, value, ...) */ static int map_marshal_write(Value *vret, Value *v, RefNode *node) { Value dumper = v[1]; Value w = Value_ref(dumper)->v[INDEX_MARSHALDUMPER_SRC]; RefMap *rm = Value_vp(*v); int is_map = FUNC_INT(node); int i; rm->lock_count++; if (!stream_write_uint32(w, rm->count)) { goto ERROR_END; } for (i = 0; i < rm->entry_num; i++) { HashValueEntry *ep = rm->entry[i]; for (; ep != NULL; ep = ep->next) { Value_push("vv", dumper, ep->key); if (!call_member_func(fs->str_write, 1, TRUE)) { goto ERROR_END; } Value_pop(); if (is_map) { Value_push("vv", dumper, ep->val); if (!call_member_func(fs->str_write, 1, TRUE)) { goto ERROR_END; } Value_pop(); } } } rm->lock_count--; return TRUE; ERROR_END: rm->lock_count--; return FALSE; }
int textio_flush(Value *vret, Value *v, RefNode *node) { Ref *ref = Value_ref(*v); Value stream = ref->v[INDEX_TEXTIO_STREAM]; RefNode *s_type = Value_type(stream); if (s_type != fs->cls_bytesio) { Value_push("v", stream); if (!call_member_func(intern("flush", -1), 0, TRUE)) { return FALSE; } } return TRUE; }
static int map_marshal_read(Value *vret, Value *v, RefNode *node) { Value dumper = v[1]; Value r = Value_ref(dumper)->v[INDEX_MARSHALDUMPER_SRC]; int is_map = FUNC_INT(node); RefMap *rm; uint32_t size; int i; if (!stream_read_uint32(r, &size)) { return FALSE; } if (size > 0xffffff) { throw_errorf(fs->mod_lang, "ValueError", "Invalid size number"); return FALSE; } if (size * sizeof(HashValueEntry) > fs->max_alloc) { throw_error_select(THROW_MAX_ALLOC_OVER__INT, fs->max_alloc); return FALSE; } rm = refmap_new(size); if (!is_map) { rm->rh.type = fs->cls_set; } *vret = vp_Value(rm); for (i = 0; i < size; i++) { Value key; Value_push("v", dumper); if (!call_member_func(fs->str_read, 0, TRUE)) { return FALSE; } fg->stk_top--; key = *fg->stk_top; if (is_map) { Value val; HashValueEntry *ve; Value_push("v", dumper); if (!call_member_func(fs->str_read, 0, TRUE)) { return FALSE; } fg->stk_top--; val = *fg->stk_top; ve = refmap_add(rm, key, TRUE, FALSE); if (ve == NULL) { unref(key); unref(val); return FALSE; } ve->val = val; } else { // Set if (refmap_add(rm, key, TRUE, FALSE) == NULL) { unref(key); return FALSE; } } unref(key); } return TRUE; }
/** * printf(format, v1, v2, ...) * printf(format, [v1, v2, ...]) * printf(format, {k1:v1, k2:v2, ...}) * * start_argは1から始まる * * v, sbどちらかが必要 */ static int textio_printf_sub(Value v, StrBuf *sb, RefStr *fmt_src, int start_arg, Ref *r_loc) { const char *p = fmt_src->c; const char *end = p + fmt_src->size; Value *varg = fg->stk_base + start_arg; int vargc = (fg->stk_top - fg->stk_base) - start_arg; HashValueEntry **vhash = NULL; Value stream; RefTextIO *tio; if (v != VALUE_NULL) { Ref *ref = Value_ref(v); stream = ref->v[INDEX_TEXTIO_STREAM]; tio = Value_vp(ref->v[INDEX_TEXTIO_TEXTIO]); } else { stream = VALUE_NULL; tio = NULL; } if (sb == NULL) { RefNode *s_type = Value_type(stream); if (s_type == fs->cls_bytesio) { sb = bytesio_get_strbuf(stream); } } // フォーマットの後の引数が1個の場合はArray,Mapを解析する if (vargc == 1) { RefNode *va_type = Value_type(*varg); if (va_type == fs->cls_map) { RefMap *r2 = Value_vp(*varg); vhash = r2->entry; vargc = r2->entry_num; // hashの場合はhash_entryサイズとして使う } else if (va_type == fs->cls_list) { RefArray *r2 = Value_vp(*varg); varg = r2->p; vargc = r2->size; } } while (p < end) { if (*p == '%') { p++; if (p >= end) { break; } if (*p == '{' || isalnum(*p) || *p == '_') { Str key; Str fmt; Value *val = NULL; if (*p == '{') { // %{key:format} p++; key.p = p; while (p < end && *p != '}' && *p != ':') { p++; } key.size = p - key.p; if (p < end && *p == ':') { p++; fmt.p = p; while (p < end && *p != '}') { p++; } fmt.size = p - fmt.p; } else { fmt.p = NULL; fmt.size = 0; } if (p < end) { p++; } } else { // $key key.p = p; while (p < end && (isalnum(*p) || *p == '_')) { p++; } key.size = p - key.p; fmt.p = NULL; fmt.size = 0; } if (vhash != NULL) { // keyに対応する値をhashから取り出す uint32_t hash = str_hash(key.p, key.size); HashValueEntry *ep = vhash[hash & (vargc - 1)]; for (; ep != NULL; ep = ep->next) { if (hash == ep->hash) { RefNode *key_type = Value_type(ep->key); if (key_type == fs->cls_str) { RefStr *rkey = Value_vp(ep->key); if (key.size == rkey->size && memcmp(key.p, rkey->c, key.size) == 0) { val = &ep->val; break; } } } } } else { // keyを整数に変換して引数のn番目から取り出す int n = parse_int(key.p, key.size, 65536); if (n >= 0 && n < vargc) { val = &varg[n]; } } if (val != NULL) { if (fmt.size > 0) { // to_strを取り出す RefNode *type = Value_type(*val); RefNode *fn = Hash_get_p(&type->u.c.h, fs->str_tostr); RefStr *vs; Value_push("vS", *val, fmt); if (r_loc != NULL) { Value_push("r", r_loc); } if (!call_function(fn, (r_loc != NULL ? 2 : 1))) { return FALSE; } vs = Value_vp(fg->stk_top[-1]); if (!stream_write_sub_s(stream, sb, vs->c, vs->size, tio)) { return FALSE; } Value_pop(); } else { if (!textio_print_sub(v, sb, *val, r_loc)) { return FALSE; } } } else { throw_errorf(fs->mod_lang, "IndexError", "Index %Q not found", key); return FALSE; } } else if (*p == '%') { // %%は%にして出力 if (!stream_write_sub_s(stream, sb, "%", 1, tio)) { return FALSE; } p++; } else { throw_errorf(fs->mod_lang, "FormatError", "Invalid character after '%%'"); return FALSE; } } else { // %が出るまでそのまま出力 const char *top = p; while (p < end && *p != '%') { p++; } if (p > top) { if (!stream_write_sub_s(stream, sb, top, p - top, tio)) { return FALSE; } } } } return TRUE; }