/** * 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; }
/** * 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; }
/** * 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; }
static int textio_print_sub(Value v_textio, StrBuf *sb, Value v, Ref *r_loc) { RefNode *v_type = Value_type(v); int result = TRUE; Value vb; RefTextIO *tio; if (v_textio != VALUE_NULL) { Ref *ref = Value_ref(v_textio); vb = ref->v[INDEX_TEXTIO_STREAM]; tio = Value_vp(ref->v[INDEX_TEXTIO_TEXTIO]); } else { vb = VALUE_NULL; tio = NULL; } // よく使う型 if (Value_isint(v)) { char c_buf[32]; sprintf(c_buf, "%d", Value_integral(v)); if (!stream_write_sub_s(vb, sb, c_buf, -1, tio)) { result = FALSE; } } else if (v_type == fs->cls_int) { RefInt *mp = Value_vp(v); char *c_buf = malloc(BigInt_str_bufsize(&mp->bi, 10)); BigInt_str(&mp->bi, 10, c_buf, FALSE); if (!stream_write_sub_s(vb, sb, c_buf, -1, tio)) { result = FALSE; } free(c_buf); } else if (v_type == fs->cls_str) { RefStr *rs = Value_vp(v); if (!stream_write_sub_s(vb, sb, rs->c, rs->size, tio)) { result = FALSE; } } else if (v_type == fv->cls_strio) { RefBytesIO *mb = Value_bytesio(v); if (!stream_write_sub_s(vb, sb, mb->buf.p, mb->buf.size, tio)) { result = FALSE; } } else if (v_type == fs->cls_module) { RefNode *nd = Value_vp(v); RefStr *rs = nd->name; if (!stream_write_sub_s(vb, sb, "Module(", 7, tio)) { return FALSE; } if (!stream_write_sub_s(vb, sb, rs->c, rs->size, tio)) { return FALSE; } if (!stream_write_sub_s(vb, sb, ")", 1, tio)) { return FALSE; } } else if (v_type != fs->cls_null) { Value vret; fs->Value_push("v", v); if (!call_member_func(fs->str_tostr, 0, TRUE)) { return FALSE; } vret = fg->stk_top[-1]; if (Value_type(vret) == fs->cls_str) { RefStr *rs = Value_vp(vret); if (!stream_write_sub_s(vb, sb, rs->c, rs->size, tio)) { return FALSE; } } else { } Value_pop(); } return result; }