summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c121
-rw-r--r--src/backtrace.c10
-rw-r--r--src/class.c303
-rw-r--r--src/codedump.c2
-rw-r--r--src/error.c186
-rw-r--r--src/etc.c36
-rw-r--r--src/gc.c8
-rw-r--r--src/hash.c22
-rw-r--r--src/kernel.c9
-rw-r--r--src/load.c5
-rw-r--r--src/numeric.c38
-rw-r--r--src/object.c37
-rw-r--r--src/proc.c8
-rw-r--r--src/range.c4
-rw-r--r--src/state.c58
-rw-r--r--src/string.c1069
-rw-r--r--src/symbol.c72
-rw-r--r--src/variable.c17
-rw-r--r--src/vm.c34
19 files changed, 1280 insertions, 759 deletions
diff --git a/src/array.c b/src/array.c
index bd9b4d358..33baceb9c 100644
--- a/src/array.c
+++ b/src/array.c
@@ -9,6 +9,8 @@
#include <mruby/class.h>
#include <mruby/string.h>
#include <mruby/range.h>
+#include <mruby/proc.h>
+#include <mruby/opcode.h>
#include "value_array.h"
#define ARY_DEFAULT_LEN 4
@@ -668,7 +670,7 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
if (n < 0) {
n += len;
if (n < 0) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of array", n - len);
}
}
if (len <= n) {
@@ -700,7 +702,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
ary_modify(mrb, a);
/* len check */
- if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len));
+ if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%i)", len);
/* range check */
if (head < 0) {
@@ -734,7 +736,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
}
if (head >= alen) {
if (head > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head);
}
len = head + argc;
if (len > ARY_CAPA(a)) {
@@ -750,7 +752,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
mrb_int newlen;
if (alen - len > ARY_MAX_SIZE - argc) {
- mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len));
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len);
}
newlen = alen + argc - len;
if (newlen > ARY_CAPA(a)) {
@@ -934,7 +936,7 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self)
mrb_ary_splice(mrb, self, i, len, v2);
break;
case MRB_RANGE_OUT:
- mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
+ mrb_raisef(mrb, E_RANGE_ERROR, "%v out of range", v1);
break;
}
return v2;
@@ -1257,44 +1259,95 @@ mrb_ary_svalue(mrb_state *mrb, mrb_value ary)
}
}
+static const mrb_code each_iseq[] = {
+ OP_ENTER, 0x0, 0x00, 0x1, /* OP_ENTER 0:0:0:0:0:0:1 */
+ OP_JMPIF, 0x1, 0x0, 19, /* OP_JMPIF R1 19 */
+ OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */
+ OP_LOADSYM, 0x4, 0x0, /* OP_LOADSYM R4 :each*/
+ OP_SEND, 0x3, 0x1, 0x1, /* OP_SEND R3 :to_enum 1 */
+ OP_RETURN, 0x3, /* OP_RETURN R3 */
+ OP_LOADI_0, 0x2, /* OP_LOADI_0 R2 */
+ OP_JMP, 0x0, 43, /* OP_JMP 49 */
+ OP_MOVE, 0x3, 0x1, /* OP_MOVE R3 R1 */
+ OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */
+ OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */
+ OP_SEND, 0x4, 0x2, 0x1, /* OP_SEND R4 :[] 1 */
+ OP_SEND, 0x3, 0x3, 0x1, /* OP_SEND R3 :call 1 */
+ OP_ADDI, 0x2, 1, /* OP_ADDI R3 1 */
+ OP_MOVE, 0x3, 0x2, /* OP_MOVE R3 R2 */
+ OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */
+ OP_SEND, 0x4, 0x4, 0x0, /* OP_SEND R4 :length 0 */
+ OP_LT, 0x3, /* OP_LT R3 */
+ OP_JMPIF, 0x3, 0x0, 24, /* OP_JMPIF R3 24 */
+ OP_RETURN, 0x0 /* OP_RETURN R3 */
+};
+
+static void
+init_ary_each(mrb_state *mrb, struct RClass *ary)
+{
+ struct RProc *p;
+ mrb_method_t m;
+ mrb_irep *each_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep));
+ static const mrb_irep mrb_irep_zero = { 0 };
+
+ *each_irep = mrb_irep_zero;
+ each_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*5);
+ each_irep->syms[0] = mrb_intern_lit(mrb, "each");
+ each_irep->syms[1] = mrb_intern_lit(mrb, "to_enum");
+ each_irep->syms[2] = mrb_intern_lit(mrb, "[]");
+ each_irep->syms[3] = mrb_intern_lit(mrb, "call");
+ each_irep->syms[4] = mrb_intern_lit(mrb, "length");
+ each_irep->slen = 5;
+ each_irep->flags = MRB_ISEQ_NO_FREE;
+ each_irep->iseq = each_iseq;
+ each_irep->ilen = sizeof(each_iseq);
+ each_irep->nregs = 7;
+ each_irep->nlocals = 3;
+ p = mrb_proc_new(mrb, each_irep);
+ MRB_METHOD_FROM_PROC(m, p);
+ mrb_define_method_raw(mrb, ary, mrb_intern_lit(mrb, "each"), m);
+}
+
void
mrb_init_array(mrb_state *mrb)
{
struct RClass *a;
- mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
+ mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
- mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
-
- mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
- mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
- mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
- mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */
- mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */
- mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
- mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */
- mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */
- mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */
- mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */
- mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */
- mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */
- mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */
- mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */
- mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
- mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
- mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
- mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
- mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
- mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
- mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */
- mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */
- mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
- mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */
- mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
+ mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
+
+ mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
+ mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
+ mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
+ mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */
+ mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */
+ mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
+ mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */
+ mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */
+ mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */
+ mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */
+ mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */
+ mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */
+ mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */
+ mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */
+ mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
+ mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
+ mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
+ mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
+ mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
+ mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
+ mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */
+ mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */
+ mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
+ mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */
+ mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */
+ mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */
mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE());
+
+ init_ary_each(mrb, a);
}
diff --git a/src/backtrace.c b/src/backtrace.c
index e4f5a3064..8001849bc 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -16,7 +16,7 @@
#include <mruby/data.h>
struct backtrace_location {
- int lineno;
+ int32_t lineno;
mrb_sym method_id;
const char *filename;
};
@@ -26,7 +26,7 @@ typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*
static const mrb_data_type bt_type = { "Backtrace", mrb_free };
static void
-each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
+each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtrace_func func, void *data)
{
ptrdiff_t i;
@@ -37,7 +37,7 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu
struct backtrace_location loc;
mrb_callinfo *ci;
mrb_irep *irep;
- mrb_code *pc;
+ const mrb_code *pc;
ci = &mrb->c->cibase[i];
@@ -246,9 +246,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
mrb_value btline;
if (entry->filename == NULL) continue;
- btline = mrb_format(mrb, "%S:%S",
- mrb_str_new_cstr(mrb, entry->filename),
- mrb_fixnum_value(entry->lineno));
+ btline = mrb_format(mrb, "%s:%d", entry->filename, entry->lineno);
if (entry->method_id != 0) {
mrb_str_cat_lit(mrb, btline, ":in ");
mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id));
diff --git a/src/class.c b/src/class.c
index 373f2aec7..a551c73f6 100644
--- a/src/class.c
+++ b/src/class.c
@@ -15,6 +15,7 @@
#include <mruby/error.h>
#include <mruby/data.h>
#include <mruby/istruct.h>
+#include <mruby/opcode.h>
KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -177,7 +178,7 @@ static void
check_if_class_or_module(mrb_state *mrb, mrb_value obj)
{
if (!class_ptr_p(obj)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj);
}
}
@@ -207,7 +208,7 @@ mrb_define_module(mrb_state *mrb, const char *name)
return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class);
}
-MRB_API struct RClass*
+struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
check_if_class_or_module(mrb, outer);
@@ -215,7 +216,7 @@ mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
mrb_value old = mrb_const_get(mrb, outer, id);
if (mrb_type(old) != MRB_TT_MODULE) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old);
}
return mrb_class_ptr(old);
}
@@ -248,9 +249,8 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
c = class_from_sym(mrb, outer, name);
MRB_CLASS_ORIGIN(c);
if (super && mrb_class_real(c->super) != super) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
- mrb_sym2str(mrb, name),
- mrb_obj_value(c->super), mrb_obj_value(super));
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)",
+ name, c->super, super);
}
return c;
}
@@ -265,7 +265,7 @@ MRB_API struct RClass*
mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super)
{
if (!super) {
- mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name));
+ mrb_warn(mrb, "no super class for '%n', Object assumed", name);
}
return define_class(mrb, name, super, mrb->object_class);
}
@@ -305,7 +305,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
}
}
-MRB_API struct RClass*
+struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
struct RClass *s;
@@ -313,8 +313,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
if (!mrb_nil_p(super)) {
if (mrb_type(super) != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)",
- mrb_inspect(mrb, super));
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super);
}
s = mrb_class_ptr(super);
}
@@ -326,13 +325,13 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
mrb_value old = mrb_const_get(mrb, outer, id);
if (mrb_type(old) != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", old);
}
c = mrb_class_ptr(old);
if (s) {
/* check super class */
if (mrb_class_real(c->super) != s) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old);
}
}
return c;
@@ -410,7 +409,7 @@ mrb_module_get(mrb_state *mrb, const char *name)
/*!
* Defines a class under the namespace of \a outer.
* \param outer a class which contains the new class.
- * \param id name of the new class
+ * \param name name of the new class
* \param super a class from which the new class will derive.
* NULL means \c Object class.
* \return the created class
@@ -431,8 +430,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
#if 0
if (!super) {
- mrb_warn(mrb, "no super class for '%S::%S', Object assumed",
- mrb_obj_value(outer), mrb_sym2str(mrb, id));
+ mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id);
}
#endif
c = define_class(mrb, id, super, outer);
@@ -489,8 +487,7 @@ mrb_notimplement(mrb_state *mrb)
mrb_callinfo *ci = mrb->c->ci;
if (ci->mid) {
- mrb_value str = mrb_sym2str(mrb, ci->mid);
- mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str);
+ mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid);
}
}
@@ -503,30 +500,17 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
-#define CHECK_TYPE(mrb, val, t, c) do { \
- if (mrb_type(val) != (t)) {\
- mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\
- }\
-} while (0)
-
-static mrb_value
-to_str(mrb_state *mrb, mrb_value val)
-{
- CHECK_TYPE(mrb, val, MRB_TT_STRING, "String");
- return val;
-}
-
static mrb_value
to_ary(mrb_state *mrb, mrb_value val)
{
- CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array");
+ mrb_check_type(mrb, val, MRB_TT_ARRAY);
return val;
}
static mrb_value
to_hash(mrb_state *mrb, mrb_value val)
{
- CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash");
+ mrb_check_type(mrb, val, MRB_TT_HASH);
return val;
}
@@ -573,20 +557,20 @@ mrb_get_argv(mrb_state *mrb)
string mruby type C type note
----------------------------------------------------------------------------------------------
o: Object [mrb_value]
- C: class/module [mrb_value]
+ C: Class/Module [mrb_value]
S: String [mrb_value] when ! follows, the value may be nil
A: Array [mrb_value] when ! follows, the value may be nil
H: Hash [mrb_value] when ! follows, the value may be nil
s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil
z: String [char*] NUL terminated string; z! gives NULL for nil
a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil
- f: Float [mrb_float]
- i: Integer [mrb_int]
- b: Boolean [mrb_bool]
- n: Symbol [mrb_sym]
- d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
- I: Inline struct [void*]
- &: Block [mrb_value] &! raises exception if no block given
+ f: Fixnum/Float [mrb_float]
+ i: Fixnum/Float [mrb_int]
+ b: boolean [mrb_bool]
+ n: String/Symbol [mrb_sym]
+ d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil
+ I: inline struct [void*]
+ &: block [mrb_value] &! raises exception if no block given
*: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
|: optional Following arguments are optional
?: optional given [mrb_bool] true if preceding argument (optional) is given
@@ -669,7 +653,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
ss = ARGV[arg_i++];
if (!class_ptr_p(ss)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss);
}
*p = ss;
i++;
@@ -690,7 +674,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
if (i < argc) {
- *p = to_str(mrb, ARGV[arg_i++]);
+ *p = ARGV[arg_i++];
+ mrb_to_str(mrb, *p);
i++;
}
}
@@ -751,7 +736,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
if (i < argc) {
- ss = to_str(mrb, ARGV[arg_i++]);
+ ss = ARGV[arg_i++];
+ mrb_to_str(mrb, ss);
*ps = RSTRING_PTR(ss);
*pl = RSTRING_LEN(ss);
i++;
@@ -773,8 +759,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
if (i < argc) {
- ss = to_str(mrb, ARGV[arg_i++]);
- *ps = mrb_string_value_cstr(mrb, &ss);
+ ss = ARGV[arg_i++];
+ mrb_to_str(mrb, ss);
+ *ps = RSTRING_CSTR(mrb, ss);
i++;
}
}
@@ -816,7 +803,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
ss = ARGV[arg_i];
if (mrb_type(ss) != MRB_TT_ISTRUCT)
{
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss);
}
*p = mrb_istruct_ptr(ss);
arg_i++;
@@ -964,7 +951,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
break;
default:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c);
break;
}
}
@@ -1070,8 +1057,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
- int changed = include_module_at(mrb, c, find_origin(c), m, 1);
- if (changed < 0) {
+ mrb_check_frozen(mrb, c);
+ if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
}
}
@@ -1082,6 +1069,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
struct RClass *origin;
int changed = 0;
+ mrb_check_frozen(mrb, c);
if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) {
origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED;
@@ -1356,21 +1344,57 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) {
inspect = mrb_any_to_s(mrb, mrb_obj_value(c));
}
- mrb_name_error(mrb, mid, "undefined method '%S' for class %S",
- mrb_sym2str(mrb, mid), inspect);
+ mrb_name_error(mrb, mid, "undefined method '%n' for class %v", mid, inspect);
}
return m;
}
+#define ONSTACK_ALLOC_MAX 32
+
+static mrb_sym
+prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix)
+{
+ char onstack[ONSTACK_ALLOC_MAX];
+ mrb_int sym_len;
+ const char *sym_str = mrb_sym2name_len(mrb, sym, &sym_len);
+ size_t prefix_len = prefix ? strlen(prefix) : 0;
+ size_t suffix_len = suffix ? strlen(suffix) : 0;
+ size_t name_len = sym_len + prefix_len + suffix_len;
+ char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack;
+ char *p = buf;
+
+ if (prefix_len > 0) {
+ memcpy(p, prefix, prefix_len);
+ p += prefix_len;
+ }
+
+ memcpy(p, sym_str, sym_len);
+ p += sym_len;
+
+ if (suffix_len > 0) {
+ memcpy(p, suffix, suffix_len);
+ p += suffix_len;
+ }
+
+ return mrb_intern(mrb, buf, name_len);
+}
+
static mrb_value
-attr_reader(mrb_state *mrb, mrb_value obj)
+prepare_ivar_name(mrb_state *mrb, mrb_sym sym)
{
- mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
- return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+ sym = prepare_name_common(mrb, sym, "@", NULL);
+ mrb_iv_name_sym_check(mrb, sym);
+ return mrb_symbol_value(sym);
+}
+
+static mrb_sym
+prepare_writer_name(mrb_state *mrb, mrb_sym sym)
+{
+ return prepare_name_common(mrb, sym, NULL, "=");
}
static mrb_value
-mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym))
{
struct RClass *c = mrb_class_ptr(mod);
mrb_value *argv;
@@ -1380,20 +1404,18 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
ai = mrb_gc_arena_save(mrb);
for (i=0; i<argc; i++) {
- mrb_value name, str;
- mrb_sym method, sym;
+ mrb_value name;
+ mrb_sym method;
struct RProc *p;
mrb_method_t m;
method = to_sym(mrb, argv[i]);
- name = mrb_sym2str(mrb, method);
- str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1);
- mrb_str_cat_lit(mrb, str, "@");
- mrb_str_cat_str(mrb, str, name);
- sym = mrb_intern_str(mrb, str);
- mrb_iv_name_sym_check(mrb, sym);
- name = mrb_symbol_value(sym);
- p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name);
+ name = prepare_ivar_name(mrb, method);
+ if (access_name) {
+ method = access_name(mrb, method);
+ }
+
+ p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name);
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, c, method, m);
mrb_gc_arena_restore(mrb, ai);
@@ -1402,6 +1424,19 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
}
static mrb_value
+attr_reader(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+}
+
+static mrb_value
+mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+{
+ return mod_attr_define(mrb, mod, attr_reader, NULL);
+}
+
+static mrb_value
attr_writer(mrb_state *mrb, mrb_value obj)
{
mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
@@ -1415,42 +1450,7 @@ attr_writer(mrb_state *mrb, mrb_value obj)
static mrb_value
mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
{
- struct RClass *c = mrb_class_ptr(mod);
- mrb_value *argv;
- mrb_int argc, i;
- int ai;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- ai = mrb_gc_arena_save(mrb);
- for (i=0; i<argc; i++) {
- mrb_value name, str, attr;
- mrb_sym method, sym;
- struct RProc *p;
- mrb_method_t m;
-
- method = to_sym(mrb, argv[i]);
-
- /* prepare iv name (@name) */
- name = mrb_sym2str(mrb, method);
- str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1);
- mrb_str_cat_lit(mrb, str, "@");
- mrb_str_cat_str(mrb, str, name);
- sym = mrb_intern_str(mrb, str);
- mrb_iv_name_sym_check(mrb, sym);
- attr = mrb_symbol_value(sym);
-
- /* prepare method name (name=) */
- str = mrb_str_new_capa(mrb, RSTRING_LEN(str));
- mrb_str_cat_str(mrb, str, name);
- mrb_str_cat_lit(mrb, str, "=");
- method = mrb_intern_str(mrb, str);
-
- p = mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr);
- MRB_METHOD_FROM_PROC(m, p);
- mrb_define_method_raw(mrb, c, method, m);
- mrb_gc_arena_restore(mrb, ai);
- }
- return mrb_nil_value();
+ return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name);
}
static mrb_value
@@ -1465,7 +1465,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
if (ttype == 0) ttype = MRB_TT_OBJECT;
if (ttype <= MRB_TT_CPTR) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv);
}
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
return mrb_obj_value(o);
@@ -1491,7 +1491,7 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv)
mrb_int argc;
mrb_sym init;
- mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+ mrb_get_args(mrb, "*!&", &argv, &argc, &blk);
obj = mrb_instance_alloc(mrb, cv);
init = mrb_intern_lit(mrb, "initialize");
if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) {
@@ -1540,7 +1540,10 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
mid = mrb_intern_lit(mrb, "initialize");
- if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
+ if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) {
+ mrb_class_initialize(mrb, new_class);
+ }
+ else {
mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
}
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
@@ -1692,7 +1695,7 @@ static void
mrb_check_inheritable(mrb_state *mrb, struct RClass *super)
{
if (super->tt != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super));
+ mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super);
}
if (super->tt == MRB_TT_SCLASS) {
mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class");
@@ -1766,6 +1769,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
/*!
* Defines an alias of a method.
+ * \param mrb the mruby state
* \param klass the class which the original method belongs to
* \param name1 a new name for the method
* \param name2 the original name of the method
@@ -1817,24 +1821,28 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod)
return mod;
}
+static void
+undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
+{
+ mrb_method_t m;
+
+ MRB_METHOD_FROM_PROC(m, NULL);
+ mrb_define_method_raw(mrb, c, a, m);
+}
+
void
mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a)
{
if (!mrb_obj_respond_to(mrb, c, a)) {
- mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c));
- }
- else {
- mrb_method_t m;
-
- MRB_METHOD_FROM_PROC(m, NULL);
- mrb_define_method_raw(mrb, c, a, m);
+ mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c);
}
+ undef_method(mrb, c, a);
}
MRB_API void
mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
{
- mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name));
+ undef_method(mrb, c, mrb_intern_cstr(mrb, name));
}
MRB_API void
@@ -1864,7 +1872,7 @@ check_const_name_sym(mrb_state *mrb, mrb_sym id)
mrb_int len;
const char *name = mrb_sym2name_len(mrb, id, &len);
if (!mrb_const_name_p(mrb, name, len)) {
- mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id));
+ mrb_name_error(mrb, id, "wrong constant name %n", id);
}
}
@@ -1921,7 +1929,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
else {
off = end + 2;
if (off == len) { /* trailing "::" */
- mrb_name_error(mrb, id, "wrong constant name '%S'", path);
+ mrb_name_error(mrb, id, "wrong constant name '%v'", path);
}
}
}
@@ -1951,7 +1959,7 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
check_const_name_sym(mrb, id);
val = mrb_iv_remove(mrb, mod, id);
if (mrb_undef_p(val)) {
- mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id));
+ mrb_name_error(mrb, id, "constant %n not defined", id);
}
return val;
}
@@ -1964,13 +1972,10 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "n", &sym);
if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
- mrb_name_error(mrb, sym, "uninitialized constant %S::%S",
- mod,
- mrb_sym2str(mrb, sym));
+ mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym);
}
else {
- mrb_name_error(mrb, sym, "uninitialized constant %S",
- mrb_sym2str(mrb, sym));
+ mrb_name_error(mrb, sym, "uninitialized constant %n", sym);
}
/* not reached */
return mrb_nil_value();
@@ -2031,7 +2036,7 @@ mod_define_method(mrb_state *mrb, mrb_value self)
/* ignored */
break;
default:
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", proc);
break;
}
if (mrb_nil_p(blk)) {
@@ -2064,6 +2069,14 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
}
static mrb_value
+mrb_mod_dup(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mod = mrb_obj_clone(mrb, self);
+ MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod));
+ return mod;
+}
+
+static mrb_value
mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
{
mrb_value *argv;
@@ -2111,6 +2124,40 @@ inspect_main(mrb_state *mrb, mrb_value mod)
return mrb_str_new_lit(mrb, "main");
}
+static const mrb_code new_iseq[] = {
+ OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */
+ OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */
+ OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */
+ OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */
+ OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */
+ OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */
+ OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R4 :initialize */
+ OP_RETURN, 0x0 /* OP_RETURN R0 */
+};
+
+static void
+init_class_new(mrb_state *mrb, struct RClass *cls)
+{
+ struct RProc *p;
+ mrb_method_t m;
+ mrb_irep *new_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep));
+ static const mrb_irep mrb_irep_zero = { 0 };
+
+ *new_irep = mrb_irep_zero;
+ new_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*2);
+ new_irep->syms[0] = mrb_intern_lit(mrb, "allocate");
+ new_irep->syms[1] = mrb_intern_lit(mrb, "initialize");
+ new_irep->slen = 2;
+ new_irep->flags = MRB_ISEQ_NO_FREE;
+ new_irep->iseq = new_iseq;
+ new_irep->ilen = sizeof(new_iseq);
+ new_irep->nregs = 6;
+ new_irep->nlocals = 3;
+ p = mrb_proc_new(mrb, new_irep);
+ MRB_METHOD_FROM_PROC(m, p);
+ mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m);
+}
+
void
mrb_init_class(mrb_state *mrb)
{
@@ -2133,7 +2180,6 @@ mrb_init_class(mrb_state *mrb)
/* name basic classes */
mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob));
- mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob));
mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj));
mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod));
mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls));
@@ -2153,16 +2199,18 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */
- mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */
+ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.5 */
mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
- mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
+ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */
- mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
+ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK());
+ mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE());
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
- mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */
mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */
mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1));
+ init_class_new(mrb, cls);
+
MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
@@ -2193,6 +2241,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1));
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */
+ mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE());
mrb_undef_method(mrb, cls, "append_features");
mrb_undef_method(mrb, cls, "extend_object");
diff --git a/src/codedump.c b/src/codedump.c
index 12d609075..b77a8adb4 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -69,7 +69,7 @@ static void
codedump(mrb_state *mrb, mrb_irep *irep)
{
int ai;
- mrb_code *pc, *pcend;
+ const mrb_code *pc, *pcend;
mrb_code ins;
const char *file = NULL, *next_file;
diff --git a/src/error.c b/src/error.c
index 4c1b67c99..2bb505d85 100644
--- a/src/error.c
+++ b/src/error.c
@@ -151,14 +151,14 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
str = mrb_str_new_cstr(mrb, cname);
if (mrb_string_p(file) && mrb_fixnum_p(line)) {
if (append_mesg) {
- str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str);
+ str = mrb_format(mrb, "%v:%v: %v (%v)", file, line, mesg, str);
}
else {
- str = mrb_format(mrb, "%S:%S: %S", file, line, str);
+ str = mrb_format(mrb, "%v:%v: %v", file, line, str);
}
}
else if (append_mesg) {
- str = mrb_format(mrb, "%S: %S", str, mesg);
+ str = mrb_format(mrb, "%v: %v", str, mesg);
}
return str;
}
@@ -198,11 +198,11 @@ static void
exc_debug_info(mrb_state *mrb, struct RObject *exc)
{
mrb_callinfo *ci = mrb->c->ci;
- mrb_code *pc = ci->pc;
+ const mrb_code *pc = ci->pc;
if (mrb_obj_iv_defined(mrb, exc, mrb_intern_lit(mrb, "file"))) return;
while (ci >= mrb->c->cibase) {
- mrb_code *err = ci->err;
+ const mrb_code *err = ci->err;
if (!err && pc) err = pc - 1;
if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
@@ -260,59 +260,152 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg)));
}
+/*
+ * <code>vsprintf</code> like formatting.
+ *
+ * The syntax of a format sequence is as follows.
+ *
+ * %[modifier]specifier
+ *
+ * The modifiers are:
+ *
+ * ----------+------------------------------------------------------------
+ * Modifier | Meaning
+ * ----------+------------------------------------------------------------
+ * ! | Convert to string by corresponding `inspect` instead of
+ * | corresponding `to_s`.
+ * ----------+------------------------------------------------------------
+ *
+ * The specifiers are:
+ *
+ * ----------+----------------+--------------------------------------------
+ * Specifier | Argument Type | Note
+ * ----------+----------------+--------------------------------------------
+ * c | char |
+ * d | int |
+ * f | mrb_float |
+ * i | mrb_int |
+ * l | char*, size_t | Arguments are string and length.
+ * n | mrb_sym |
+ * s | char* | Argument is NUL terminated string.
+ * t | mrb_value | Convert to type (class) of object.
+ * v,S | mrb_value |
+ * C | struct RClass* |
+ * T | mrb_value | Convert to real type (class) of object.
+ * Y | mrb_value | Same as `!v` if argument is `true`, `false`
+ * | | or `nil`, otherwise same as `T`.
+ * % | - | Convert to percent sign itself (no argument
+ * | | taken).
+ * ----------+----------------+--------------------------------------------
+ */
MRB_API mrb_value
mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
{
- const char *p = format;
- const char *b = p;
- ptrdiff_t size;
- int ai0 = mrb_gc_arena_save(mrb);
- mrb_value ary = mrb_ary_new_capa(mrb, 4);
+ const char *chars, *p = format, *b = format, *e;
+ char ch;
+ size_t len;
+ mrb_int i;
+ struct RClass *cls;
+ mrb_bool inspect = FALSE;
+ mrb_value result = mrb_str_new_capa(mrb, 128), obj, str;
int ai = mrb_gc_arena_save(mrb);
while (*p) {
const char c = *p++;
-
+ e = p;
if (c == '%') {
- if (*p == 'S') {
- mrb_value val;
-
- size = p - b - 1;
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
- val = va_arg(ap, mrb_value);
- mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val));
- b = p + 1;
- }
- }
- else if (c == '\\') {
- if (*p) {
- size = p - b - 1;
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
- b = ++p;
+ if (*p == '!') {
+ inspect = TRUE;
+ ++p;
}
- else {
- break;
+ if (!*p) break;
+ switch (*p) {
+ case 'c':
+ ch = (char)va_arg(ap, int);
+ chars = &ch;
+ len = 1;
+ goto L_cat;
+ case 'd': case 'i':
+#if MRB_INT_MAX < INT_MAX
+ i = (mrb_int)va_arg(ap, int);
+#else
+ i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int);
+#endif
+ obj = mrb_fixnum_value(i);
+ goto L_cat_obj;
+#ifndef MRB_WITHOUT_FLOAT
+ case 'f':
+ obj = mrb_float_value(mrb, (mrb_float)va_arg(ap, double));
+ goto L_cat_obj;
+#endif
+ case 'l':
+ chars = va_arg(ap, char*);
+ len = va_arg(ap, size_t);
+ L_cat:
+ if (inspect) {
+ obj = mrb_str_new(mrb, chars, len);
+ goto L_cat_obj;
+ }
+ mrb_str_cat(mrb, result, b, e - b - 1);
+ mrb_str_cat(mrb, result, chars, len);
+ b = ++p;
+ mrb_gc_arena_restore(mrb, ai);
+ break;
+ case 'n':
+ obj = mrb_symbol_value(va_arg(ap, mrb_sym));
+ goto L_cat_obj;
+ case 's':
+ chars = va_arg(ap, char*);
+ len = strlen(chars);
+ goto L_cat;
+ case 't':
+ cls = mrb_class(mrb, va_arg(ap, mrb_value));
+ goto L_cat_class;
+ case 'v': case 'S':
+ obj = va_arg(ap, mrb_value);
+ L_cat_obj:
+ str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj);
+ chars = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+ inspect = FALSE;
+ goto L_cat;
+ case 'C':
+ cls = va_arg(ap, struct RClass*);
+ L_cat_class:
+ obj = mrb_obj_value(cls);
+ goto L_cat_obj;
+ case 'T':
+ obj = va_arg(ap, mrb_value);
+ L_cat_real_class_of:
+ cls = mrb_obj_class(mrb, obj);
+ goto L_cat_class;
+ case 'Y':
+ obj = va_arg(ap, mrb_value);
+ if (!mrb_test(obj) || mrb_true_p(obj)) {
+ inspect = TRUE;
+ goto L_cat_obj;
+ }
+ else {
+ goto L_cat_real_class_of;
+ }
+ case '%':
+ L_cat_current:
+ chars = p;
+ len = 1;
+ goto L_cat;
+ default:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p);
}
}
- mrb_gc_arena_restore(mrb, ai);
- }
- if (b == format) {
- mrb_gc_arena_restore(mrb, ai0);
- return mrb_str_new_cstr(mrb, format);
- }
- else {
- mrb_value val;
+ else if (c == '\\') {
+ if (!*p) break;
+ goto L_cat_current;
- size = p - b;
- if (size > 0) {
- mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
}
- val = mrb_ary_join(mrb, ary, mrb_nil_value());
- mrb_gc_arena_restore(mrb, ai0);
- mrb_gc_protect(mrb, val);
- return val;
}
+
+ mrb_str_cat(mrb, result, b, p - b);
+ return result;
}
MRB_API mrb_value
@@ -434,7 +527,7 @@ exception_call:
break;
default:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 0..3)", argc);
break;
}
if (argc > 0) {
@@ -487,8 +580,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
MRB_API mrb_noreturn void
mrb_frozen_error(mrb_state *mrb, void *frozen_obj)
{
- mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S",
- mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj))));
+ mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", mrb_obj_value(frozen_obj));
}
void
diff --git a/src/etc.c b/src/etc.c
index ac1540f92..bf6586748 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -1,5 +1,5 @@
/*
-** etc.c -
+** etc.c
**
** See Copyright Notice in mruby.h
*/
@@ -8,8 +8,6 @@
#include <mruby/string.h>
#include <mruby/data.h>
#include <mruby/class.h>
-#include <mruby/re.h>
-#include <mruby/irep.h>
MRB_API struct RData*
mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
@@ -33,14 +31,12 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
const mrb_data_type *t2 = DATA_TYPE(obj);
if (t2) {
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)",
- mrb_str_new_cstr(mrb, t2->struct_name), mrb_str_new_cstr(mrb, type->struct_name));
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)",
+ t2->struct_name, type->struct_name);
}
else {
- struct RClass *c = mrb_class(mrb, obj);
-
- mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)",
- mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name));
+ mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)",
+ obj, type->struct_name);
}
}
}
@@ -67,24 +63,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
MRB_API mrb_sym
mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
{
- mrb_sym id;
-
- switch (mrb_type(name)) {
- default:
- name = mrb_check_string_type(mrb, name);
- if (mrb_nil_p(name)) {
- name = mrb_inspect(mrb, name);
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name);
- /* not reached */
- }
- /* fall through */
- case MRB_TT_STRING:
- name = mrb_str_intern(mrb, name);
- /* fall through */
- case MRB_TT_SYMBOL:
- id = mrb_symbol(name);
- }
- return id;
+ if (mrb_symbol_p(name)) return mrb_symbol(name);
+ if (mrb_string_p(name)) return mrb_intern_str(mrb, name);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a symbol nor a string", name);
+ return 0; /* not reached */
}
MRB_API mrb_int
diff --git a/src/gc.c b/src/gc.c
index 94068c0f9..a2a904477 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -506,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
for (i = 0; i < ARY_LEN(a); i++) {
- if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) {
+ if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) {
mrb_int len = ARY_LEN(a)-1;
mrb_value *ptr = ARY_PTR(a);
@@ -521,7 +521,7 @@ MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{
struct RBasic *p;
- static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
+ static const RVALUE RVALUE_zero = { { { NULL, NULL, MRB_TT_FALSE } } };
mrb_gc *gc = &mrb->gc;
if (cls) {
@@ -542,7 +542,7 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != tt) {
- mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
+ mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls);
}
}
@@ -748,7 +748,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
break;
case MRB_TT_STRING:
- if (RSTR_FSHARED_P(obj) && !RSTR_NOFREE_P(obj)) {
+ if (RSTR_FSHARED_P(obj)) {
struct RString *s = (struct RString*)obj;
mrb_gc_mark(mrb, (struct RBasic*)s->as.heap.aux.fshared);
}
diff --git a/src/hash.c b/src/hash.c
index a9367a426..2a0a19363 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -240,7 +240,7 @@ ht_compact(mrb_state *mrb, htable *t)
if (!seg->next && i >= t->last_len) {
goto exit;
}
- if (mrb_undef_p(k)) { /* found delete key */
+ if (mrb_undef_p(k)) { /* found deleted key */
if (seg2 == NULL) {
seg2 = seg;
i2 = i;
@@ -546,6 +546,7 @@ ht_copy(mrb_state *mrb, htable *t)
if ((seg->next == NULL) && (i >= t->last_len)) {
return t2;
}
+ if (mrb_undef_p(key)) continue; /* skip deleted key */
ht_put(mrb, t2, key, val);
}
seg = seg->next;
@@ -1378,10 +1379,21 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
* values of key objects have changed since they were inserted, this
* method will reindex <i>hsh</i>.
*
- * h = {"AAA" => "b"}
- * h.keys[0].chop!
- * h.rehash #=> {"AA"=>"b"}
- * h["AA"] #=> "b"
+ * keys = (1..17).map{|n| [n]}
+ * k = keys[0]
+ * h = {}
+ * keys.each{|key| h[key] = key[0]}
+ * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7,
+ * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14,
+ * [15]=>15,[16]=>16,[17]=>17}
+ * h[k] #=> 1
+ * k[0] = keys.size + 1
+ * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7,
+ * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14,
+ * [15]=>15,[16]=>16,[17]=>17}
+ * h[k] #=> nil
+ * h.rehash
+ * h[k] #=> 1
*/
static mrb_value
mrb_hash_rehash(mrb_state *mrb, mrb_value self)
diff --git a/src/kernel.c b/src/kernel.c
index a3c2d2ec6..f0935a2f8 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -325,7 +325,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self)
mrb_value clone;
if (mrb_immediate_p(self)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %v", self);
}
if (mrb_type(self) == MRB_TT_SCLASS) {
mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class");
@@ -366,7 +366,7 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj)
mrb_value dup;
if (mrb_immediate_p(obj)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %v", obj);
}
if (mrb_type(obj) == MRB_TT_SCLASS) {
mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class");
@@ -641,7 +641,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
mrb_iv_name_sym_check(mrb, sym);
val = mrb_iv_remove(mrb, self, sym);
if (mrb_undef_p(val)) {
- mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym));
+ mrb_name_error(mrb, sym, "instance variable %n not defined", sym);
}
return val;
}
@@ -649,7 +649,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
void
mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
{
- mrb_no_method_error(mrb, name, args, "undefined method '%S'", mrb_sym2str(mrb, name));
+ mrb_no_method_error(mrb, name, args, "undefined method '%n'", name);
}
/* 15.3.1.3.30 */
@@ -805,5 +805,4 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */
mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
- mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */
}
diff --git a/src/load.c b/src/load.c
index 97eafdbb5..2aa2c576f 100644
--- a/src/load.c
+++ b/src/load.c
@@ -102,8 +102,9 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
}
else {
size_t data_len = sizeof(mrb_code) * irep->ilen;
- irep->iseq = (mrb_code *)mrb_malloc(mrb, data_len);
- memcpy(irep->iseq, src, data_len);
+ void *buf = mrb_malloc(mrb, data_len);
+ irep->iseq = (mrb_code *)buf;
+ memcpy(buf, src, data_len);
src += data_len;
}
}
diff --git a/src/numeric.c b/src/numeric.c
index 0d1c23589..638f75fd8 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -172,17 +172,17 @@ integral_div(mrb_state *mrb, mrb_value x)
static mrb_value
integral_coerce_step_counter(mrb_state *mrb, mrb_value self)
{
- mrb_value counter = self, num, step;
+ mrb_value num, step;
mrb_get_args(mrb, "oo", &num, &step);
#ifndef MRB_WITHOUT_FLOAT
if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
- counter = mrb_funcall(mrb, counter, "to_f", 0);
+ return mrb_Float(mrb, self);
}
#endif
- return counter;
+ return self;
}
#ifndef MRB_WITHOUT_FLOAT
@@ -246,9 +246,6 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
str = mrb_float_to_str(mrb, flt, fmt);
goto insert_dot_zero;
}
- else {
- mrb_str_cat(mrb, str, ".0", 2);
- }
return str;
}
@@ -320,6 +317,8 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
div = (x - mod) / y;
if (modp && divp) div = round(div);
}
+ if (div == 0) div = 0.0;
+ if (mod == 0) mod = 0.0;
if (y*mod < 0) {
mod += y;
div -= 1.0;
@@ -702,6 +701,7 @@ flo_round(mrb_state *mrb, mrb_value num)
f = 1.0;
i = ndigits >= 0 ? ndigits : -ndigits;
+ if (ndigits > DBL_DIG+2) return num;
while (--i >= 0)
f = f*10.0;
@@ -888,22 +888,24 @@ static mrb_value
fix_mod(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_int a;
+ mrb_int a, b;
mrb_get_args(mrb, "o", &y);
a = mrb_fixnum(x);
- if (mrb_fixnum_p(y)) {
- mrb_int b, mod;
+ if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
+ mrb_int mod;
- if ((b=mrb_fixnum(y)) == 0) {
+ if (b == 0) {
#ifdef MRB_WITHOUT_FLOAT
/* ZeroDivisionError */
return mrb_fixnum_value(0);
#else
+ if (a > 0) return mrb_float_value(mrb, INFINITY);
+ if (a < 0) return mrb_float_value(mrb, INFINITY);
return mrb_float_value(mrb, NAN);
#endif
}
- fixdivmod(mrb, a, b, 0, &mod);
+ fixdivmod(mrb, a, b, NULL, &mod);
return mrb_fixnum_value(mod);
}
#ifdef MRB_WITHOUT_FLOAT
@@ -912,7 +914,7 @@ fix_mod(mrb_state *mrb, mrb_value x)
else {
mrb_float mod;
- flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
+ flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -1118,7 +1120,7 @@ lshift(mrb_state *mrb, mrb_int val, mrb_int width)
}
else {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
- (val < (MRB_INT_MIN >> width))) {
+ (val <= (MRB_INT_MIN >> width))) {
#ifdef MRB_WITHOUT_FLOAT
return mrb_fixnum_value(0);
#else
@@ -1252,7 +1254,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
z = (mrb_int)d;
}
else {
- mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x);
+ mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
}
}
return mrb_fixnum_value(z);
@@ -1384,7 +1386,7 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
mrb_int val = mrb_fixnum(x);
if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
}
if (val == 0) {
@@ -1493,12 +1495,10 @@ integral_cmp(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(n);
}
-static void
+static mrb_noreturn void
cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %S with %S failed",
- mrb_obj_value(mrb_class(mrb, v1)),
- mrb_obj_value(mrb_class(mrb, v2)));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
}
static mrb_value
diff --git a/src/object.c b/src/object.c
index 7c1879019..ee36da320 100644
--- a/src/object.c
+++ b/src/object.c
@@ -297,17 +297,6 @@ mrb_init_object(mrb_state *mrb)
}
static mrb_value
-inspect_type(mrb_state *mrb, mrb_value val)
-{
- if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) {
- return mrb_inspect(mrb, val);
- }
- else {
- return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val));
- }
-}
-
-static mrb_value
convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise)
{
mrb_sym m = 0;
@@ -315,7 +304,7 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho
m = mrb_intern_cstr(mrb, method);
if (!mrb_respond_to(mrb, val, m)) {
if (raise) {
- mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname));
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into %s", val, tname);
}
return mrb_nil_value();
}
@@ -330,8 +319,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char
if (mrb_type(val) == type) return val;
v = convert_type(mrb, val, tname, method, TRUE);
if (mrb_type(v) != type) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val,
- mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%s", val, tname, method);
}
return v;
}
@@ -405,13 +393,12 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
else {
etype = mrb_obj_classname(mrb, x);
}
- mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)",
- mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name));
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)",
+ etype, type->name);
}
type++;
}
- mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)",
- mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x)));
+ mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %d (%d given)", t, mrb_type(x));
}
}
@@ -499,15 +486,12 @@ mrb_to_int(mrb_state *mrb, mrb_value val)
{
if (!mrb_fixnum_p(val)) {
- mrb_value type;
-
#ifndef MRB_WITHOUT_FLOAT
if (mrb_float_p(val)) {
return mrb_flo_to_fixnum(mrb, val);
}
#endif
- type = inspect_type(mrb, val);
- mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type);
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y to Integer", val);
}
return val;
}
@@ -598,8 +582,7 @@ MRB_API mrb_value
mrb_ensure_string_type(mrb_state *mrb, mrb_value str)
{
if (!mrb_string_p(str)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String",
- inspect_type(mrb, str));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to String", str);
}
return str;
}
@@ -615,8 +598,7 @@ MRB_API mrb_value
mrb_ensure_array_type(mrb_state *mrb, mrb_value ary)
{
if (!mrb_array_p(ary)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array",
- inspect_type(mrb, ary));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Array", ary);
}
return ary;
}
@@ -632,8 +614,7 @@ MRB_API mrb_value
mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash)
{
if (!mrb_hash_p(hash)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash",
- inspect_type(mrb, hash));
+ mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Hash", hash);
}
return hash;
}
diff --git a/src/proc.c b/src/proc.c
index 094fff816..ca398384f 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -9,7 +9,7 @@
#include <mruby/proc.h>
#include <mruby/opcode.h>
-static mrb_code call_iseq[] = {
+static const mrb_code call_iseq[] = {
OP_CALL,
};
@@ -153,8 +153,8 @@ mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv.");
}
if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) {
- mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)",
- mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e)));
+ mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %i (expected: 0 <= index < %i)",
+ idx, MRB_ENV_STACK_LEN(e));
}
return e->stack[idx];
@@ -256,7 +256,7 @@ mrb_int
mrb_proc_arity(const struct RProc *p)
{
struct mrb_irep *irep;
- mrb_code *pc;
+ const mrb_code *pc;
mrb_aspec aspec;
int ma, op, ra, pa, arity;
diff --git a/src/range.c b/src/range.c
index 9036ef093..28862d779 100644
--- a/src/range.c
+++ b/src/range.c
@@ -92,7 +92,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m
if (r) {
if (RANGE_INITIALIZED_P(r)) {
/* Ranges are immutable, so that they should be initialized only once. */
- mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice");
+ mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice");
}
else {
range_ptr_alloc_edges(mrb, r);
@@ -363,7 +363,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
}
}
else {
- mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]);
+ mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %v", argv[i]);
}
}
diff --git a/src/state.c b/src/state.c
index c42df71ba..99b523dd5 100644
--- a/src/state.c
+++ b/src/state.c
@@ -117,7 +117,7 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
int i;
if (!(irep->flags & MRB_ISEQ_NO_FREE))
- mrb_free(mrb, irep->iseq);
+ mrb_free(mrb, (void*)irep->iseq);
if (irep->pool) for (i=0; i<irep->plen; i++) {
if (mrb_type(irep->pool[i]) == MRB_TT_STRING) {
mrb_gc_free_str(mrb, RSTRING(irep->pool[i]));
@@ -141,58 +141,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
mrb_free(mrb, irep);
}
-mrb_value
-mrb_str_pool(mrb_state *mrb, mrb_value str)
-{
- struct RString *s = mrb_str_ptr(str);
- struct RString *ns;
- char *ptr;
- mrb_int len;
-
- ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString));
- ns->tt = MRB_TT_STRING;
- ns->c = mrb->string_class;
-
- if (RSTR_NOFREE_P(s)) {
- ns->flags = MRB_STR_NOFREE;
- ns->as.heap.ptr = s->as.heap.ptr;
- ns->as.heap.len = s->as.heap.len;
- ns->as.heap.aux.capa = 0;
- }
- else {
- ns->flags = 0;
- if (RSTR_EMBED_P(s)) {
- ptr = s->as.ary;
- len = RSTR_EMBED_LEN(s);
- }
- else {
- ptr = s->as.heap.ptr;
- len = s->as.heap.len;
- }
-
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(ns);
- RSTR_SET_EMBED_LEN(ns, len);
- if (ptr) {
- memcpy(ns->as.ary, ptr, len);
- }
- ns->as.ary[len] = '\0';
- }
- else {
- ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- ns->as.heap.len = len;
- ns->as.heap.aux.capa = len;
- if (ptr) {
- memcpy(ns->as.heap.ptr, ptr, len);
- }
- ns->as.heap.ptr[len] = '\0';
- }
- }
- RSTR_SET_POOL_FLAG(ns);
- MRB_SET_FROZEN_FLAG(ns);
- return mrb_obj_value(ns);
-}
-
void mrb_free_backtrace(mrb_state *mrb);
MRB_API void
@@ -221,10 +169,10 @@ mrb_close(mrb_state *mrb)
}
/* free */
- mrb_gc_free_gv(mrb);
+ mrb_gc_destroy(mrb, &mrb->gc);
mrb_free_context(mrb, mrb->root_c);
+ mrb_gc_free_gv(mrb);
mrb_free_symtbl(mrb);
- mrb_gc_destroy(mrb, &mrb->gc);
mrb_free(mrb, mrb);
}
diff --git a/src/string.c b/src/string.c
index bfe73b359..c1c28ee8b 100644
--- a/src/string.c
+++ b/src/string.c
@@ -21,13 +21,11 @@
#include <mruby/range.h>
#include <mruby/string.h>
#include <mruby/numeric.h>
-#include <mruby/re.h>
typedef struct mrb_shared_string {
- mrb_bool nofree : 1;
int refcnt;
+ mrb_int capa;
char *ptr;
- mrb_int len;
} mrb_shared_string;
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
@@ -35,55 +33,114 @@ const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
static struct RString*
-str_new_static(mrb_state *mrb, const char *p, size_t len)
+str_init_normal_capa(mrb_state *mrb, struct RString *s,
+ const char *p, size_t len, size_t capa)
{
- struct RString *s;
+ char *dst = (char *)mrb_malloc(mrb, capa + 1);
+ if (p) memcpy(dst, p, len);
+ dst[len] = '\0';
+ s->as.heap.ptr = dst;
+ s->as.heap.len = (mrb_int)len;
+ s->as.heap.aux.capa = (mrb_int)capa;
+ RSTR_UNSET_TYPE_FLAG(s);
+ return s;
+}
- if (len >= MRB_INT_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
- }
- s = mrb_obj_alloc_string(mrb);
+static struct RString*
+str_init_normal(mrb_state *mrb, struct RString *s, const char *p, size_t len)
+{
+ return str_init_normal_capa(mrb, s, p, len, len);
+}
+
+static struct RString*
+str_init_embed(struct RString *s, const char *p, size_t len)
+{
+ if (p) memcpy(RSTR_EMBED_PTR(s), p, len);
+ RSTR_EMBED_PTR(s)[len] = '\0';
+ RSTR_SET_TYPE_FLAG(s, EMBED);
+ RSTR_SET_EMBED_LEN(s, len);
+ return s;
+}
+
+static struct RString*
+str_init_nofree(struct RString *s, const char *p, size_t len)
+{
+ s->as.heap.ptr = (char *)p;
s->as.heap.len = (mrb_int)len;
s->as.heap.aux.capa = 0; /* nofree */
- s->as.heap.ptr = (char *)p;
- s->flags = MRB_STR_NOFREE;
+ RSTR_SET_TYPE_FLAG(s, NOFREE);
+ return s;
+}
+static struct RString*
+str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, mrb_shared_string *shared)
+{
+ if (shared) {
+ shared->refcnt++;
+ }
+ else {
+ shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
+ shared->refcnt = 1;
+ shared->ptr = orig->as.heap.ptr;
+ shared->capa = orig->as.heap.aux.capa;
+ }
+ s->as.heap.ptr = orig->as.heap.ptr;
+ s->as.heap.len = orig->as.heap.len;
+ s->as.heap.aux.shared = shared;
+ RSTR_SET_TYPE_FLAG(s, SHARED);
return s;
}
static struct RString*
-str_new(mrb_state *mrb, const char *p, size_t len)
+str_init_fshared(const struct RString *orig, struct RString *s, struct RString *fshared)
{
- struct RString *s;
+ s->as.heap.ptr = orig->as.heap.ptr;
+ s->as.heap.len = orig->as.heap.len;
+ s->as.heap.aux.fshared = fshared;
+ RSTR_SET_TYPE_FLAG(s, FSHARED);
+ return s;
+}
- if (p && mrb_ro_data_p(p)) {
- return str_new_static(mrb, p, len);
- }
- s = mrb_obj_alloc_string(mrb);
- if (len <= RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- if (p) {
- memcpy(s->as.ary, p, len);
- }
+static struct RString*
+str_init_modifiable(mrb_state *mrb, struct RString *s, const char *p, size_t len)
+{
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(s, p, len);
}
else {
- if (len >= MRB_INT_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
- }
- s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1);
- s->as.heap.len = (mrb_int)len;
- s->as.heap.aux.capa = (mrb_int)len;
- if (p) {
- memcpy(s->as.heap.ptr, p, len);
- }
+ return str_init_normal(mrb, s, p, len);
}
- RSTR_PTR(s)[len] = '\0';
- return s;
+}
+
+static struct RString*
+str_new_static(mrb_state *mrb, const char *p, size_t len)
+{
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(mrb_obj_alloc_string(mrb), p, len);
+ }
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ return str_init_nofree(mrb_obj_alloc_string(mrb), p, len);
+}
+
+static struct RString*
+str_new(mrb_state *mrb, const char *p, size_t len)
+{
+ if (RSTR_EMBEDDABLE_P(len)) {
+ return str_init_embed(mrb_obj_alloc_string(mrb), p, len);
+ }
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ if (p && mrb_ro_data_p(p)) {
+ return str_init_nofree(mrb_obj_alloc_string(mrb), p, len);
+ }
+ return str_init_normal(mrb, mrb_obj_alloc_string(mrb), p, len);
}
static inline void
-str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj)
+str_with_class(struct RString *s, mrb_value obj)
{
s->c = mrb_str_ptr(obj)->c;
}
@@ -93,7 +150,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str)
{
struct RString *s = str_new(mrb, 0, 0);
- str_with_class(mrb, s, str);
+ str_with_class(s, str);
return mrb_obj_value(s);
}
@@ -102,15 +159,17 @@ mrb_str_new_capa(mrb_state *mrb, size_t capa)
{
struct RString *s;
- s = mrb_obj_alloc_string(mrb);
-
- if (capa >= MRB_INT_MAX) {
+ if (RSTR_EMBEDDABLE_P(capa)) {
+ s = str_init_embed(mrb_obj_alloc_string(mrb), NULL, 0);
+ }
+ else if (capa >= MRB_INT_MAX) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big");
+ /* not reached */
+ s = NULL;
+ }
+ else {
+ s = str_init_normal_capa(mrb, mrb_obj_alloc_string(mrb), NULL, 0, capa);
}
- s->as.heap.len = 0;
- s->as.heap.aux.capa = (mrb_int)capa;
- s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1);
- RSTR_PTR(s)[0] = '\0';
return mrb_obj_value(s);
}
@@ -135,14 +194,8 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity)
mrb_assert(capacity < MRB_INT_MAX);
#endif
if (RSTR_EMBED_P(s)) {
- if (RSTRING_EMBED_LEN_MAX < capacity) {
- char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
- const mrb_int len = RSTR_EMBED_LEN(s);
- memcpy(tmp, s->as.ary, len);
- RSTR_UNSET_EMBED_FLAG(s);
- s->as.heap.ptr = tmp;
- s->as.heap.len = len;
- s->as.heap.aux.capa = (mrb_int)capacity;
+ if (!RSTR_EMBEDDABLE_P(capacity)) {
+ str_init_normal_capa(mrb, s, RSTR_EMBED_PTR(s), RSTR_EMBED_LEN(s), capacity);
}
}
else {
@@ -187,9 +240,7 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared)
{
shared->refcnt--;
if (shared->refcnt == 0) {
- if (!shared->nofree) {
- mrb_free(mrb, shared->ptr);
- }
+ mrb_free(mrb, shared->ptr);
mrb_free(mrb, shared);
}
}
@@ -233,8 +284,10 @@ utf8len(const char* p, const char* e)
mrb_int len;
mrb_int i;
+ if ((unsigned char)*p < 0x80) return 1;
len = utf8len_codepage[(unsigned char)*p];
- if (p + len > e) return 1;
+ if (len == 1) return 1;
+ if (len > e - p) return 1;
for (i = 1; i < len; ++i)
if ((p[i] & 0xc0) != 0x80)
return 1;
@@ -258,14 +311,15 @@ mrb_utf8_len(const char *str, mrb_int byte_len)
static mrb_int
utf8_strlen(mrb_value str)
{
- mrb_int byte_len = RSTRING_LEN(str);
+ struct RString *s = mrb_str_ptr(str);
+ mrb_int byte_len = RSTR_LEN(s);
- if (RSTRING(str)->flags & MRB_STR_NO_UTF) {
+ if (RSTR_ASCII_P(s)) {
return byte_len;
}
else {
- mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len);
- if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF;
+ mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len);
+ if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s);
return utf8_len;
}
}
@@ -290,25 +344,136 @@ chars2bytes(mrb_value s, mrb_int off, mrb_int idx)
/* map byte offset to character index */
static mrb_int
-bytes2chars(char *p, mrb_int bi)
+bytes2chars(char *p, mrb_int len, mrb_int bi)
{
- mrb_int i, b, n;
+ const char *e = p + (size_t)len;
+ const char *pivot = p + bi;
+ mrb_int i;
- for (b=i=0; b<bi; i++) {
- n = utf8len_codepage[(unsigned char)*p];
- b += n;
- p += n;
+ for (i = 0; p < pivot; i ++) {
+ p += utf8len(p, e);
}
- if (b != bi) return -1;
+ if (p != pivot) return -1;
return i;
}
+static const char *
+char_adjust(const char *beg, const char *end, const char *ptr)
+{
+ if ((ptr > beg || ptr < end) && (*ptr & 0xc0) == 0x80) {
+ const int utf8_adjust_max = 3;
+ const char *p;
+
+ if (ptr - beg > utf8_adjust_max) {
+ beg = ptr - utf8_adjust_max;
+ }
+
+ p = ptr;
+ while (p > beg) {
+ p --;
+ if ((*p & 0xc0) != 0x80) {
+ int clen = utf8len(p, end);
+ if (clen > ptr - p) return p;
+ break;
+ }
+ }
+ }
+
+ return ptr;
+}
+
+static const char *
+char_backtrack(const char *ptr, const char *end)
+{
+ if (ptr < end) {
+ const int utf8_bytelen_max = 4;
+ const char *p;
+
+ if (end - ptr > utf8_bytelen_max) {
+ ptr = end - utf8_bytelen_max;
+ }
+
+ p = end;
+ while (p > ptr) {
+ p --;
+ if ((*p & 0xc0) != 0x80) {
+ int clen = utf8len_codepage[(unsigned char)*p];
+ if (clen == end - p) { return p; }
+ break;
+ }
+ }
+ }
+
+ return end - 1;
+}
+
+static mrb_int
+str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off)
+{
+ /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */
+
+ ptrdiff_t qstable[1 << CHAR_BIT];
+
+ /* Preprocessing */
+ {
+ mrb_int i;
+
+ for (i = 0; i < 1 << CHAR_BIT; i ++) {
+ qstable[i] = slen;
+ }
+ for (i = 0; i < slen; i ++) {
+ qstable[(unsigned char)s[i]] = slen - (i + 1);
+ }
+ }
+
+ /* Searching */
+ while (p < pend && pend - p >= slen) {
+ const char *pivot;
+
+ if (memcmp(p, s, slen) == 0) {
+ return off;
+ }
+
+ pivot = p + qstable[(unsigned char)p[slen - 1]];
+ if (pivot > pend || pivot < p /* overflowed */) { return -1; }
+
+ do {
+ p += utf8len(p, pend);
+ off ++;
+ } while (p < pivot);
+ }
+
+ return -1;
+}
+
+static mrb_int
+str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
+{
+ const char *p = RSTRING_PTR(str);
+ const char *pend = p + RSTRING_LEN(str);
+ const char *s = RSTRING_PTR(sub);
+ const mrb_int slen = RSTRING_LEN(sub);
+ mrb_int off = pos;
+
+ for (; pos > 0; pos --) {
+ if (pend - p < 1) { return -1; }
+ p += utf8len(p, pend);
+ }
+
+ if (slen < 1) { return off; }
+
+ return str_index_str_by_char_search(mrb, p, pend, s, slen, off);
+}
+
#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value();
#else
#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
#define chars2bytes(p, off, ci) (ci)
-#define bytes2chars(p, bi) (bi)
+#define bytes2chars(p, end, bi) (bi)
+#define char_adjust(beg, end, ptr) (ptr)
+#define char_backtrack(ptr, end) ((end) - 1)
#define BYTES_ALIGN_CHECK(pos)
+#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos)
#endif
static inline mrb_int
@@ -358,108 +523,114 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
static void
str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s)
{
- mrb_shared_string *shared;
- mrb_int len = RSTR_LEN(orig);
+ size_t len = (size_t)orig->as.heap.len;
mrb_assert(!RSTR_EMBED_P(orig));
- if (RSTR_SHARED_P(orig)) {
- shared = orig->as.heap.aux.shared;
- shared->refcnt++;
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.shared = shared;
- RSTR_SET_SHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ if (RSTR_NOFREE_P(orig)) {
+ str_init_nofree(s, orig->as.heap.ptr, len);
+ }
+ else if (RSTR_SHARED_P(orig)) {
+ str_init_shared(mrb, orig, s, orig->as.heap.aux.shared);
}
else if (RSTR_FSHARED_P(orig)) {
- struct RString *fs;
-
- fs = orig->as.heap.aux.fshared;
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.fshared = fs;
- RSTR_SET_FSHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ str_init_fshared(orig, s, orig->as.heap.aux.fshared);
}
else if (MRB_FROZEN_P(orig) && !RSTR_POOL_P(orig)) {
- s->as.heap.ptr = orig->as.heap.ptr;
- s->as.heap.len = len;
- s->as.heap.aux.fshared = orig;
- RSTR_SET_FSHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ str_init_fshared(orig, s, orig);
}
else {
- shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
- shared->refcnt = 2;
- shared->nofree = !!RSTR_NOFREE_P(orig);
- if (!shared->nofree && orig->as.heap.aux.capa > orig->as.heap.len) {
- shared->ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1);
- orig->as.heap.ptr = shared->ptr;
- }
- else {
- shared->ptr = orig->as.heap.ptr;
+ if (orig->as.heap.aux.capa > orig->as.heap.len) {
+ orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1);
+ orig->as.heap.aux.capa = len;
}
- orig->as.heap.aux.shared = shared;
- RSTR_SET_SHARED_FLAG(orig);
- shared->len = len;
- s->as.heap.aux.shared = shared;
- s->as.heap.ptr = shared->ptr;
- s->as.heap.len = len;
- RSTR_SET_SHARED_FLAG(s);
- RSTR_UNSET_EMBED_FLAG(s);
+ str_init_shared(mrb, orig, s, NULL);
+ str_init_shared(mrb, orig, orig, s->as.heap.aux.shared);
}
}
-static mrb_value
-byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+mrb_value
+mrb_str_pool(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = (struct RString *)mrb_malloc(mrb, sizeof(struct RString));
+ struct RString *orig = mrb_str_ptr(str);
+ const char *p = RSTR_PTR(orig);
+ size_t len = (size_t)RSTR_LEN(orig);
+
+ s->tt = MRB_TT_STRING;
+ s->c = mrb->string_class;
+ s->flags = 0;
+
+ if (RSTR_EMBEDDABLE_P(len)) {
+ str_init_embed(s, p, len);
+ }
+ else if (RSTR_NOFREE_P(orig)) {
+ str_init_nofree(s, p, len);
+ }
+ else {
+ str_init_normal(mrb, s, p, len);
+ }
+ RSTR_SET_POOL_FLAG(s);
+ MRB_SET_FROZEN_FLAG(s);
+ return mrb_obj_value(s);
+}
+
+mrb_value
+mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
{
struct RString *orig, *s;
orig = mrb_str_ptr(str);
- if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || len <= RSTRING_EMBED_LEN_MAX) {
- s = str_new(mrb, RSTR_PTR(orig)+beg, len);
+ s = mrb_obj_alloc_string(mrb);
+ if (RSTR_EMBEDDABLE_P(len)) {
+ str_init_embed(s, RSTR_PTR(orig)+beg, len);
}
else {
- s = mrb_obj_alloc_string(mrb);
str_make_shared(mrb, orig, s);
s->as.heap.ptr += beg;
s->as.heap.len = len;
}
+ RSTR_COPY_ASCII_FLAG(s, orig);
return mrb_obj_value(s);
}
+
+static void
+str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len)
+{
+ *pos = chars2bytes(str, 0, *pos);
+ *len = chars2bytes(str, *pos, *len);
+}
#ifdef MRB_UTF8_STRING
static inline mrb_value
str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
{
- beg = chars2bytes(str, 0, beg);
- len = chars2bytes(str, beg, len);
-
- return byte_subseq(mrb, str, beg, len);
+ str_range_to_bytes(str, &beg, &len);
+ return mrb_str_byte_subseq(mrb, str, beg, len);
}
#else
-#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len)
+#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len)
#endif
-static mrb_value
-str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+mrb_bool
+mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp)
{
- mrb_int clen = RSTRING_CHAR_LEN(str);
-
- if (len < 0) return mrb_nil_value();
- if (clen == 0) {
- len = 0;
+ if (str_len < *begp || *lenp < 0) return FALSE;
+ if (*begp < 0) {
+ *begp += str_len;
+ if (*begp < 0) return FALSE;
}
- if (beg > clen) return mrb_nil_value();
- if (beg < 0) {
- beg += clen;
- if (beg < 0) return mrb_nil_value();
+ if (*lenp > str_len - *begp)
+ *lenp = str_len - *begp;
+ if (*lenp <= 0) {
+ *lenp = 0;
}
- if (len > clen - beg)
- len = clen - beg;
- if (len <= 0) {
- len = 0;
- }
- return str_subseq(mrb, str, beg, len);
+ return TRUE;
+}
+
+static mrb_value
+str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ?
+ str_subseq(mrb, str, beg, len) : mrb_nil_value();
}
MRB_API mrb_int
@@ -502,30 +673,22 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset)
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
- mrb_int len;
+ size_t len;
mrb_check_frozen(mrb, s1);
if (s1 == s2) return mrb_obj_value(s1);
- s1->flags &= ~MRB_STR_NO_UTF;
- s1->flags |= s2->flags&MRB_STR_NO_UTF;
- len = RSTR_LEN(s2);
+ RSTR_COPY_ASCII_FLAG(s1, s2);
if (RSTR_SHARED_P(s1)) {
str_decref(mrb, s1->as.heap.aux.shared);
- RSTR_UNSET_SHARED_FLAG(s1);
}
else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1) && !RSTR_FSHARED_P(s1)
&& s1->as.heap.ptr) {
mrb_free(mrb, s1->as.heap.ptr);
}
- RSTR_UNSET_FSHARED_FLAG(s1);
- RSTR_UNSET_NOFREE_FLAG(s1);
- if (len <= RSTRING_EMBED_LEN_MAX) {
- RSTR_UNSET_SHARED_FLAG(s1);
- RSTR_UNSET_FSHARED_FLAG(s1);
- RSTR_SET_EMBED_FLAG(s1);
- memcpy(s1->as.ary, RSTR_PTR(s2), len);
- RSTR_SET_EMBED_LEN(s1, len);
+ len = (size_t)RSTR_LEN(s2);
+ if (RSTR_EMBEDDABLE_P(len)) {
+ str_init_embed(s1, RSTR_PTR(s2), len);
}
else {
str_make_shared(mrb, s2, s1);
@@ -537,7 +700,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
static mrb_int
str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
{
- char *s, *sbeg, *t;
+ const char *s, *sbeg, *t;
struct RString *ps = mrb_str_ptr(str);
mrb_int len = RSTRING_LEN(sub);
@@ -550,11 +713,12 @@ str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
s = RSTR_PTR(ps) + pos;
t = RSTRING_PTR(sub);
if (len) {
+ s = char_adjust(sbeg, sbeg + RSTR_LEN(ps), s);
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
return (mrb_int)(s - RSTR_PTR(ps));
}
- s--;
+ s = char_backtrack(sbeg, s);
}
return -1;
}
@@ -642,67 +806,34 @@ mrb_locale_from_utf8(const char *utf8, int len)
#endif
MRB_API void
-mrb_str_modify(mrb_state *mrb, struct RString *s)
+mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s)
{
mrb_check_frozen(mrb, s);
- s->flags &= ~MRB_STR_NO_UTF;
if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
- if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
- s->as.heap.ptr = shared->ptr;
- s->as.heap.aux.capa = shared->len;
- RSTR_PTR(s)[s->as.heap.len] = '\0';
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.aux.capa = shared->capa;
+ s->as.heap.ptr[s->as.heap.len] = '\0';
mrb_free(mrb, shared);
}
else {
- char *ptr, *p;
- mrb_int len;
-
- p = RSTR_PTR(s);
- len = s->as.heap.len;
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- ptr = RSTR_PTR(s);
- }
- else {
- ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
- s->as.heap.ptr = ptr;
- s->as.heap.aux.capa = len;
- }
- if (p) {
- memcpy(ptr, p, len);
- }
- ptr[len] = '\0';
+ str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len);
str_decref(mrb, shared);
}
- RSTR_UNSET_SHARED_FLAG(s);
- return;
}
- if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) {
- char *p = s->as.heap.ptr;
- mrb_int len = s->as.heap.len;
-
- RSTR_UNSET_FSHARED_FLAG(s);
- RSTR_UNSET_NOFREE_FLAG(s);
- RSTR_UNSET_FSHARED_FLAG(s);
- if (len < RSTRING_EMBED_LEN_MAX) {
- RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s, len);
- }
- else {
- s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- s->as.heap.aux.capa = len;
- }
- if (p) {
- memcpy(RSTR_PTR(s), p, len);
- }
- RSTR_PTR(s)[len] = '\0';
- return;
+ else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) {
+ str_init_modifiable(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len);
}
}
+MRB_API void
+mrb_str_modify(mrb_state *mrb, struct RString *s)
+{
+ mrb_str_modify_keep_ascii(mrb, s);
+ RSTR_UNSET_ASCII_FLAG(s);
+}
+
MRB_API mrb_value
mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
{
@@ -824,7 +955,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
len = RSTRING_LEN(self)*times;
str2 = str_new(mrb, 0, len);
- str_with_class(mrb, str2, self);
+ str_with_class(str2, self);
p = RSTR_PTR(str2);
if (len > 0) {
n = RSTRING_LEN(self);
@@ -836,6 +967,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
memcpy(p + n, p, len-n);
}
p[RSTR_LEN(str2)] = '\0';
+ RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self));
return mrb_obj_value(str2);
}
@@ -973,6 +1105,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str)
switch (mrb_type(str)) {
case MRB_TT_STRING:
return str;
+ case MRB_TT_SYMBOL:
+ return mrb_sym2str(mrb, mrb_symbol(str));
case MRB_TT_FIXNUM:
return mrb_fixnum_to_str(mrb, str, 10);
case MRB_TT_CLASS:
@@ -983,6 +1117,7 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str)
}
}
+/* obslete: use RSTRING_PTR() */
MRB_API const char*
mrb_string_value_ptr(mrb_state *mrb, mrb_value str)
{
@@ -990,6 +1125,7 @@ mrb_string_value_ptr(mrb_state *mrb, mrb_value str)
return RSTRING_PTR(str);
}
+/* obslete: use RSTRING_LEN() */
MRB_API mrb_int
mrb_string_value_len(mrb_state *mrb, mrb_value ptr)
{
@@ -1003,55 +1139,95 @@ mrb_str_dup(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
struct RString *dup = str_new(mrb, 0, 0);
- str_with_class(mrb, dup, str);
+ str_with_class(dup, str);
return str_replace(mrb, dup, s);
}
-static mrb_value
-mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx)
-{
- mrb_int idx;
+enum str_convert_range {
+ /* `beg` and `len` are byte unit in `0 ... str.bytesize` */
+ STR_BYTE_RANGE_CORRECTED = 1,
- switch (mrb_type(indx)) {
- case MRB_TT_FIXNUM:
- idx = mrb_fixnum(indx);
+ /* `beg` and `len` are char unit in any range */
+ STR_CHAR_RANGE = 2,
-num_index:
- str = str_substr(mrb, str, idx, 1);
- if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value();
- return str;
+ /* `beg` and `len` are char unit in `0 ... str.size` */
+ STR_CHAR_RANGE_CORRECTED = 3,
- case MRB_TT_STRING:
- if (str_index_str(mrb, str, indx, 0) != -1)
- return mrb_str_dup(mrb, indx);
- return mrb_nil_value();
+ /* `beg` is out of range */
+ STR_OUT_OF_RANGE = -1
+};
+
+static enum str_convert_range
+str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len)
+{
+ if (!mrb_undef_p(alen)) {
+ *beg = mrb_int(mrb, indx);
+ *len = mrb_int(mrb, alen);
+ return STR_CHAR_RANGE;
+ }
+ else {
+ switch (mrb_type(indx)) {
+ case MRB_TT_FIXNUM:
+ *beg = mrb_fixnum(indx);
+ *len = 1;
+ return STR_CHAR_RANGE;
- case MRB_TT_RANGE:
- goto range_arg;
+ case MRB_TT_STRING:
+ *beg = str_index_str(mrb, str, indx, 0);
+ if (*beg < 0) { break; }
+ *len = RSTRING_LEN(indx);
+ return STR_BYTE_RANGE_CORRECTED;
- default:
- indx = mrb_Integer(mrb, indx);
- if (mrb_nil_p(indx)) {
- range_arg:
- {
- mrb_int beg, len;
-
- len = RSTRING_CHAR_LEN(str);
- switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) {
+ case MRB_TT_RANGE:
+ goto range_arg;
+
+ default:
+ indx = mrb_to_int(mrb, indx);
+ if (mrb_fixnum_p(indx)) {
+ *beg = mrb_fixnum(indx);
+ *len = 1;
+ return STR_CHAR_RANGE;
+ }
+range_arg:
+ *len = RSTRING_CHAR_LEN(str);
+ switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) {
case MRB_RANGE_OK:
- return str_subseq(mrb, str, beg, len);
+ return STR_CHAR_RANGE_CORRECTED;
case MRB_RANGE_OUT:
- return mrb_nil_value();
+ return STR_OUT_OF_RANGE;
default:
break;
- }
}
+
mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum");
+ }
+ }
+ return STR_OUT_OF_RANGE;
+}
+
+static mrb_value
+mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen)
+{
+ mrb_int beg, len;
+
+ switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) {
+ case STR_CHAR_RANGE_CORRECTED:
+ return str_subseq(mrb, str, beg, len);
+ case STR_CHAR_RANGE:
+ str = str_substr(mrb, str, beg, len);
+ if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value();
+ return str;
+ case STR_BYTE_RANGE_CORRECTED:
+ if (mrb_string_p(indx)) {
+ return mrb_str_dup(mrb, indx);
+ }
+ else {
+ return mrb_str_byte_subseq(mrb, str, beg, len);
}
- idx = mrb_fixnum(indx);
- goto num_index;
+ case STR_OUT_OF_RANGE:
+ default:
+ return mrb_nil_value();
}
- return mrb_nil_value(); /* not reached */
}
/* 15.2.10.5.6 */
@@ -1098,16 +1274,118 @@ static mrb_value
mrb_str_aref_m(mrb_state *mrb, mrb_value str)
{
mrb_value a1, a2;
- mrb_int argc;
- argc = mrb_get_args(mrb, "o|o", &a1, &a2);
- if (argc == 2) {
- mrb_int n1, n2;
+ if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) {
+ a2 = mrb_undef_value();
+ }
+
+ return mrb_str_aref(mrb, str, a1, a2);
+}
+
+static mrb_noreturn void
+str_out_of_index(mrb_state *mrb, mrb_value index)
+{
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %v out of string", index);
+}
+
+static mrb_value
+str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep)
+{
+ const mrb_int shrink_threshold = 256;
+ struct RString *str = mrb_str_ptr(src);
+ mrb_int len = RSTR_LEN(str);
+ mrb_int replen, newlen;
+ char *strp;
- mrb_get_args(mrb, "ii", &n1, &n2);
- return str_substr(mrb, str, n1, n2);
+ if (end > len) { end = len; }
+
+ if (pos < 0 || pos > len) {
+ str_out_of_index(mrb, mrb_fixnum_value(pos));
+ }
+
+ replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep));
+ newlen = replen + len - (end - pos);
+
+ if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big");
}
- return mrb_str_aref(mrb, str, a1);
+
+ mrb_str_modify(mrb, str);
+
+ if (len < newlen) {
+ resize_capa(mrb, str, newlen);
+ }
+
+ strp = RSTR_PTR(str);
+
+ memmove(strp + newlen - (len - end), strp + end, len - end);
+ if (!mrb_nil_p(rep)) {
+ memmove(strp + pos, RSTRING_PTR(rep), replen);
+ }
+ RSTR_SET_LEN(str, newlen);
+ strp[newlen] = '\0';
+
+ if (len - newlen >= shrink_threshold) {
+ resize_capa(mrb, str, newlen);
+ }
+
+ return src;
+}
+
+static void
+mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace)
+{
+ mrb_int beg, len, charlen;
+
+ mrb_to_str(mrb, replace);
+
+ switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) {
+ case STR_OUT_OF_RANGE:
+ default:
+ mrb_raise(mrb, E_INDEX_ERROR, "string not matched");
+ case STR_CHAR_RANGE:
+ if (len < 0) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "negative length %v", alen);
+ }
+ charlen = RSTRING_CHAR_LEN(str);
+ if (beg < 0) { beg += charlen; }
+ if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); }
+ /* fall through */
+ case STR_CHAR_RANGE_CORRECTED:
+ str_range_to_bytes(str, &beg, &len);
+ /* fall through */
+ case STR_BYTE_RANGE_CORRECTED:
+ str_replace_partial(mrb, str, beg, beg + len, replace);
+ }
+}
+
+/*
+ * call-seq:
+ * str[fixnum] = replace
+ * str[fixnum, fixnum] = replace
+ * str[range] = replace
+ * str[regexp] = replace
+ * str[regexp, fixnum] = replace
+ * str[other_str] = replace
+ *
+ * Modify +self+ by replacing the content of +self+.
+ * The portion of the string affected is determined using the same criteria as +String#[]+.
+ */
+static mrb_value
+mrb_str_aset_m(mrb_state *mrb, mrb_value str)
+{
+ mrb_value indx, alen, replace;
+
+ switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) {
+ case 2:
+ replace = alen;
+ alen = mrb_undef_value();
+ break;
+ case 3:
+ break;
+ }
+ mrb_str_aset(mrb, str, indx, alen, replace);
+ return str;
}
/* 15.2.10.5.8 */
@@ -1130,7 +1408,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
mrb_bool modify = FALSE;
struct RString *s = mrb_str_ptr(str);
- mrb_str_modify(mrb, s);
+ mrb_str_modify_keep_ascii(mrb, s);
if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value();
p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s);
if (ISLOWER(*p)) {
@@ -1189,7 +1467,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
argc = mrb_get_args(mrb, "|S", &rs);
- mrb_str_modify(mrb, s);
+ mrb_str_modify_keep_ascii(mrb, s);
len = RSTR_LEN(s);
if (argc == 0) {
if (len == 0) return mrb_nil_value();
@@ -1288,7 +1566,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
- mrb_str_modify(mrb, s);
+ mrb_str_modify_keep_ascii(mrb, s);
if (RSTR_LEN(s) > 0) {
mrb_int len;
#ifdef MRB_UTF8_STRING
@@ -1357,7 +1635,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
mrb_bool modify = FALSE;
struct RString *s = mrb_str_ptr(str);
- mrb_str_modify(mrb, s);
+ mrb_str_modify_keep_ascii(mrb, s);
p = RSTR_PTR(s);
pend = RSTR_PTR(s) + RSTR_LEN(s);
while (p < pend) {
@@ -1514,31 +1792,26 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_index_m(mrb_state *mrb, mrb_value str)
{
- mrb_value *argv;
- mrb_int argc;
mrb_value sub;
- mrb_int pos, clen;
+ mrb_int pos;
- mrb_get_args(mrb, "*!", &argv, &argc);
- if (argc == 2) {
- mrb_get_args(mrb, "oi", &sub, &pos);
- }
- else {
- pos = 0;
- if (argc > 0)
- sub = argv[0];
- else
+ switch (mrb_get_args(mrb, "|oi", &sub, &pos)) {
+ case 0:
sub = mrb_nil_value();
+ /* fall through */
+ case 1:
+ pos = 0;
+ break;
+ case 2:
+ if (pos < 0) {
+ mrb_int clen = RSTRING_CHAR_LEN(str);
+ pos += clen;
+ if (pos < 0) {
+ return mrb_nil_value();
+ }
+ }
+ break;
}
- clen = RSTRING_CHAR_LEN(str);
- if (pos < 0) {
- pos += clen;
- if (pos < 0) {
- return mrb_nil_value();
- }
- }
- if (pos > clen) return mrb_nil_value();
- pos = chars2bytes(str, 0, pos);
switch (mrb_type(sub)) {
default: {
@@ -1546,18 +1819,17 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
tmp = mrb_check_string_type(mrb, sub);
if (mrb_nil_p(tmp)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub);
+ mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub);
}
sub = tmp;
}
/* fall through */
case MRB_TT_STRING:
- pos = str_index_str(mrb, str, sub, pos);
+ pos = str_index_str_by_char(mrb, str, sub, pos);
break;
}
if (pos == -1) return mrb_nil_value();
- pos = bytes2chars(RSTRING_PTR(str), pos);
BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
@@ -1671,6 +1943,18 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
return mrb_obj_value(p_str);
}
+static inline void
+str_reverse(char *p, char *e)
+{
+ char c;
+
+ while (p < e) {
+ c = *p;
+ *p++ = *e;
+ *e-- = c;
+ }
+}
+
/* 15.2.10.5.30 */
/*
* call-seq:
@@ -1681,53 +1965,38 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
static mrb_value
mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
{
+ struct RString *s = mrb_str_ptr(str);
+ char *p, *e;
+
#ifdef MRB_UTF8_STRING
mrb_int utf8_len = RSTRING_CHAR_LEN(str);
- mrb_int len = RSTRING_LEN(str);
-
- if (utf8_len == len) goto bytes;
- if (utf8_len > 1) {
- char *buf;
- char *p, *e, *r;
-
- mrb_str_modify(mrb, mrb_str_ptr(str));
- len = RSTRING_LEN(str);
- buf = (char*)mrb_malloc(mrb, (size_t)len);
- p = buf;
- e = buf + len;
-
- memcpy(buf, RSTRING_PTR(str), len);
- r = RSTRING_PTR(str) + len;
+ mrb_int len = RSTR_LEN(s);
+ if (utf8_len < 2) return str;
+ if (utf8_len < len) {
+ mrb_str_modify(mrb, s);
+ p = RSTR_PTR(s);
+ e = p + RSTR_LEN(s);
while (p<e) {
mrb_int clen = utf8len(p, e);
- r -= clen;
- memcpy(r, p, clen);
+ str_reverse(p, p + clen - 1);
p += clen;
}
- mrb_free(mrb, buf);
+ goto bytes;
}
- return str;
-
- bytes:
#endif
- {
- struct RString *s = mrb_str_ptr(str);
- char *p, *e;
- char c;
+ if (RSTR_LEN(s) > 1) {
mrb_str_modify(mrb, s);
- if (RSTR_LEN(s) > 1) {
- p = RSTR_PTR(s);
- e = p + RSTR_LEN(s) - 1;
- while (p < e) {
- c = *p;
- *p++ = *e;
- *e-- = c;
- }
- }
- return str;
+ goto bytes;
}
+ return str;
+
+ bytes:
+ p = RSTR_PTR(s);
+ e = p + RSTR_LEN(s) - 1;
+ str_reverse(p, e);
+ return str;
}
/* ---------------------------------- */
@@ -1770,28 +2039,25 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
static mrb_value
mrb_str_rindex(mrb_state *mrb, mrb_value str)
{
- mrb_value *argv;
- mrb_int argc;
mrb_value sub;
mrb_int pos, len = RSTRING_CHAR_LEN(str);
- mrb_get_args(mrb, "*!", &argv, &argc);
- if (argc == 2) {
- mrb_get_args(mrb, "oi", &sub, &pos);
- if (pos < 0) {
- pos += len;
+ switch (mrb_get_args(mrb, "|oi", &sub, &pos)) {
+ case 0:
+ sub = mrb_nil_value();
+ /* fall through */
+ case 1:
+ pos = len;
+ break;
+ case 2:
if (pos < 0) {
- return mrb_nil_value();
+ pos += len;
+ if (pos < 0) {
+ return mrb_nil_value();
+ }
}
- }
- if (pos > len) pos = len;
- }
- else {
- pos = len;
- if (argc > 0)
- sub = argv[0];
- else
- sub = mrb_nil_value();
+ if (pos > len) pos = len;
+ break;
}
pos = chars2bytes(str, 0, pos);
@@ -1801,7 +2067,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
tmp = mrb_check_string_type(mrb, sub);
if (mrb_nil_p(tmp)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub);
+ mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub);
}
sub = tmp;
}
@@ -1809,7 +2075,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
case MRB_TT_STRING:
pos = str_rindex(mrb, str, sub, pos);
if (pos >= 0) {
- pos = bytes2chars(RSTRING_PTR(str), pos);
+ pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos);
BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
@@ -1917,7 +2183,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
else if (ISSPACE(c)) {
- mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg));
+ mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg));
mrb_gc_arena_restore(mrb, ai);
skip = TRUE;
beg = idx;
@@ -1942,7 +2208,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
else {
end = chars2bytes(str, idx, 1);
}
- mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end));
+ mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end));
mrb_gc_arena_restore(mrb, ai);
idx += end + pat_len;
if (lim_p && lim <= ++i) break;
@@ -1954,7 +2220,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
tmp = mrb_str_new_empty(mrb, str);
}
else {
- tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
+ tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
}
mrb_ary_push(mrb, result, tmp);
}
@@ -2052,7 +2318,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
break;
default:
if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base);
}
break;
} /* end of switch (base) { */
@@ -2112,8 +2378,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
else
#endif
{
- mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer",
- mrb_str_new(mrb, str, pend-str));
+ mrb_raisef(mrb, E_RANGE_ERROR, "string (%l) too big for integer", str, pend-str);
}
}
}
@@ -2129,8 +2394,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base,
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
/* not reached */
bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)",
- mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str)));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%!l)", str, pend-str);
/* not reached */
return mrb_fixnum_value(0);
}
@@ -2141,6 +2405,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec
return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck);
}
+/* obslete: use RSTRING_CSTR() or mrb_string_cstr() */
MRB_API const char*
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
@@ -2155,16 +2420,23 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
if (p[len] == '\0') {
return p;
}
+ if (MRB_FROZEN_P(ps) || RSTR_CAPA(ps) == len) {
+ ps = str_new(mrb, NULL, len+1);
+ memcpy(RSTR_PTR(ps), p, len);
+ RSTR_SET_LEN(ps, len);
+ *ptr = mrb_obj_value(ps);
+ }
else {
- if (MRB_FROZEN_P(ps)) {
- ps = str_new(mrb, p, len);
- *ptr = mrb_obj_value(ps);
- }
- else {
- mrb_str_modify(mrb, ps);
- }
- return RSTR_PTR(ps);
+ mrb_str_modify(mrb, ps);
}
+ RSTR_PTR(ps)[len] = '\0';
+ return RSTR_PTR(ps);
+}
+
+MRB_API const char*
+mrb_string_cstr(mrb_state *mrb, mrb_value str)
+{
+ return mrb_string_value_cstr(mrb, &str);
}
MRB_API mrb_value
@@ -2173,7 +2445,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
const char *s;
mrb_int len;
- s = mrb_string_value_ptr(mrb, str);
+ mrb_to_str(mrb, str);
+ s = RSTRING_PTR(str);
len = RSTRING_LEN(str);
return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
}
@@ -2206,7 +2479,7 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "|i", &base);
if (base < 0) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base);
}
return mrb_str_to_inum(mrb, self, base, FALSE);
}
@@ -2231,7 +2504,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
if (p == end) {
if (badcheck) {
bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%s)", p);
/* not reached */
}
return d;
@@ -2278,7 +2551,7 @@ bad:
MRB_API double
mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
{
- return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck);
+ return mrb_cstr_to_dbl(mrb, RSTRING_CSTR(mrb, str), badcheck);
}
/* 15.2.10.5.39 */
@@ -2333,7 +2606,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str)
char *p, *pend;
mrb_bool modify = FALSE;
- mrb_str_modify(mrb, s);
+ mrb_str_modify_keep_ascii(mrb, s);
p = RSTRING_PTR(str);
pend = RSTRING_END(str);
while (p < pend) {
@@ -2414,7 +2687,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
}
result = str_new(mrb, 0, len);
- str_with_class(mrb, result, str);
+ str_with_class(result, str);
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
q = RSTR_PTR(result);
*q++ = '"';
@@ -2576,6 +2849,9 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
const char *p, *pend;
char buf[CHAR_ESC_LEN + 1];
mrb_value result = mrb_str_new_lit(mrb, "\"");
+#ifdef MRB_UTF8_STRING
+ uint32_t ascii_flag = MRB_STR_ASCII;
+#endif
p = RSTRING_PTR(str); pend = RSTRING_END(str);
for (;p < pend; p++) {
@@ -2592,6 +2868,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
}
mrb_str_cat(mrb, result, buf, clen);
p += clen-1;
+ ascii_flag = 0;
continue;
}
#endif
@@ -2633,6 +2910,10 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
}
}
mrb_str_cat_lit(mrb, result, "\"");
+#ifdef MRB_UTF8_STRING
+ mrb_str_ptr(str)->flags |= ascii_flag;
+ mrb_str_ptr(result)->flags |= ascii_flag;
+#endif
return result;
}
@@ -2660,13 +2941,112 @@ mrb_str_bytes(mrb_state *mrb, mrb_value str)
return a;
}
+/*
+ * call-seq:
+ * str.getbyte(index) -> 0 .. 255
+ *
+ * returns the <i>index</i>th byte as an integer.
+ */
+static mrb_value
+mrb_str_getbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos;
+ mrb_get_args(mrb, "i", &pos);
+
+ if (pos < 0)
+ pos += RSTRING_LEN(str);
+ if (pos < 0 || RSTRING_LEN(str) <= pos)
+ return mrb_nil_value();
+
+ return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]);
+}
+
+/*
+ * call-seq:
+ * str.setbyte(index, integer) -> integer
+ *
+ * modifies the <i>index</i>th byte as <i>integer</i>.
+ */
+static mrb_value
+mrb_str_setbyte(mrb_state *mrb, mrb_value str)
+{
+ mrb_int pos, byte;
+ mrb_int len;
+
+ mrb_get_args(mrb, "ii", &pos, &byte);
+
+ len = RSTRING_LEN(str);
+ if (pos < -len || len <= pos)
+ mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of string", pos);
+ if (pos < 0)
+ pos += len;
+
+ mrb_str_modify(mrb, mrb_str_ptr(str));
+ byte &= 0xff;
+ RSTRING_PTR(str)[pos] = (unsigned char)byte;
+ return mrb_fixnum_value((unsigned char)byte);
+}
+
+/*
+ * call-seq:
+ * str.byteslice(integer) -> new_str or nil
+ * str.byteslice(integer, integer) -> new_str or nil
+ * str.byteslice(range) -> new_str or nil
+ *
+ * Byte Reference---If passed a single Integer, returns a
+ * substring of one byte at that position. If passed two Integer
+ * objects, returns a substring starting at the offset given by the first, and
+ * a length given by the second. If given a Range, a substring containing
+ * bytes at offsets given by the range is returned. In all three cases, if
+ * an offset is negative, it is counted from the end of <i>str</i>. Returns
+ * <code>nil</code> if the initial offset falls outside the string, the length
+ * is negative, or the beginning of the range is greater than the end.
+ * The encoding of the resulted string keeps original encoding.
+ *
+ * "hello".byteslice(1) #=> "e"
+ * "hello".byteslice(-1) #=> "o"
+ * "hello".byteslice(1, 2) #=> "el"
+ * "\x80\u3042".byteslice(1, 3) #=> "\u3042"
+ * "\x03\u3042\xff".byteslice(1..3) #=> "\u3042"
+ */
+static mrb_value
+mrb_str_byteslice(mrb_state *mrb, mrb_value str)
+{
+ mrb_value a1, a2;
+ mrb_int str_len = RSTRING_LEN(str), beg, len;
+ mrb_bool empty = TRUE;
+
+ if (mrb_get_args(mrb, "o|o", &a1, &a2) == 2) {
+ beg = mrb_fixnum(mrb_to_int(mrb, a1));
+ len = mrb_fixnum(mrb_to_int(mrb, a2));
+ }
+ else if (mrb_type(a1) == MRB_TT_RANGE) {
+ if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) != MRB_RANGE_OK) {
+ return mrb_nil_value();
+ }
+ }
+ else {
+ beg = mrb_fixnum(mrb_to_int(mrb, a1));
+ len = 1;
+ empty = FALSE;
+ }
+
+ if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) {
+ return mrb_str_byte_subseq(mrb, str, beg, len);
+ }
+ else {
+ return mrb_nil_value();
+ }
+}
+
/* ---------------------------*/
void
mrb_init_string(mrb_state *mrb)
{
struct RClass *s;
- mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string");
+ mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << MRB_STR_EMBED_LEN_BITSIZE),
+ "pointer size too big for embedded string");
mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
@@ -2678,6 +3058,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */
mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */
mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */
+ mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY());
mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */
mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */
mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */
@@ -2715,6 +3096,10 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */
mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
}
#ifndef MRB_WITHOUT_FLOAT
diff --git a/src/symbol.c b/src/symbol.c
index b26f2b1fd..aad250f09 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -20,6 +20,22 @@ typedef struct symbol_name {
const char *name;
} symbol_name;
+#define SYMBOL_INLINE_BIT 1
+#define SYMBOL_INLINE_LOWER_BIT 2
+#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1))
+#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1))
+#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT
+#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT
+#ifdef MRB_ENABLE_ALL_SYMBOLS
+# define SYMBOL_INLINE_P(sym) FALSE
+# define SYMBOL_INLINE_LOWER_P(sym) FALSE
+# define sym_inline_pack(name, len) 0
+# define sym_inline_unpack(sym, buf, lenp) NULL
+#else
+# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE)
+# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER)
+#endif
+
static void
sym_validate_len(mrb_state *mrb, size_t len)
{
@@ -41,7 +57,7 @@ sym_inline_pack(const char *name, uint16_t len)
const char *p;
int i;
mrb_sym sym = 0;
- int lower = 1;
+ mrb_bool lower = TRUE;
if (len > lower_length_max) return 0; /* too long */
for (i=0; i<len; i++) {
@@ -52,9 +68,9 @@ sym_inline_pack(const char *name, uint16_t len)
p = strchr(pack_table, (int)c);
if (p == 0) return 0; /* non alnum char */
bits = (uint32_t)(p - pack_table)+1;
- if (bits > 27) lower = 0;
+ if (bits > 27) lower = FALSE;
if (i >= mix_length_max) break;
- sym |= bits<<(i*6+2);
+ sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT);
}
if (lower) {
sym = 0;
@@ -64,24 +80,24 @@ sym_inline_pack(const char *name, uint16_t len)
c = name[i];
p = strchr(pack_table, (int)c);
bits = (uint32_t)(p - pack_table)+1;
- sym |= bits<<(i*5+2);
+ sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT);
}
- return sym | 3;
+ return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER;
}
if (len > mix_length_max) return 0;
- return sym | 1;
+ return sym | SYMBOL_INLINE;
}
static const char*
sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp)
{
- int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */
+ int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6;
int i;
- mrb_assert(sym&1);
+ mrb_assert(SYMBOL_INLINE_P(sym));
for (i=0; i<30/bit_per_char; i++) {
- uint32_t bits = sym>>(i*bit_per_char+2) & ((1<<bit_per_char)-1);
+ uint32_t bits = sym>>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1<<bit_per_char)-1);
if (bits == 0) break;
buf[i] = pack_table[bits-1];;
}
@@ -113,25 +129,23 @@ find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash)
mrb_sym i;
symbol_name *sname;
-#ifndef MRB_ENABLE_ALL_SYMBOLS
/* inline symbol */
i = sym_inline_pack(name, len);
if (i > 0) return i;
-#endif
i = mrb->symhash[hash];
if (i == 0) return 0;
do {
sname = &mrb->symtbl[i];
if (sname->len == len && memcmp(sname->name, name, len) == 0) {
- return i<<1;
+ return i<<SYMBOL_NORMAL_SHIFT;
}
if (sname->prev == 0xff) {
i -= 0xff;
sname = &mrb->symtbl[i];
while (mrb->symtbl < sname) {
if (sname->len == len && memcmp(sname->name, name, len) == 0) {
- return (mrb_sym)(sname - mrb->symtbl)<<1;
+ return (mrb_sym)(sname - mrb->symtbl)<<SYMBOL_NORMAL_SHIFT;
}
sname--;
}
@@ -186,7 +200,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
}
mrb->symhash[hash] = sym;
- return sym<<1;
+ return sym<<SYMBOL_NORMAL_SHIFT;
}
MRB_API mrb_sym
@@ -239,13 +253,9 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str)
static const char*
sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp)
{
-#ifndef MRB_ENABLE_ALL_SYMBOLS
- if (sym & 1) { /* inline packed symbol */
- return sym_inline_unpack(sym, buf, lenp);
- }
-#endif
+ if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp);
- sym >>= 1;
+ sym >>= SYMBOL_NORMAL_SHIFT;
if (sym == 0 || mrb->symidx < sym) {
if (lenp) *lenp = 0;
return NULL;
@@ -484,15 +494,18 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
name = mrb_sym2name_len(mrb, id, &len);
str = mrb_str_new(mrb, 0, len+1);
sp = RSTRING_PTR(str);
- RSTRING_PTR(str)[0] = ':';
+ sp[0] = ':';
memcpy(sp+1, name, len);
mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
if (!symname_p(name) || strlen(name) != (size_t)len) {
- str = mrb_str_dump(mrb, str);
+ str = mrb_str_inspect(mrb, str);
sp = RSTRING_PTR(str);
sp[0] = ':';
sp[1] = '"';
}
+#ifdef MRB_UTF8_STRING
+ if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+#endif
return str;
}
@@ -503,8 +516,10 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym)
const char *name = mrb_sym2name_len(mrb, sym, &len);
if (!name) return mrb_undef_value(); /* can't happen */
- if (sym&1) { /* inline symbol */
- return mrb_str_new(mrb, name, len);
+ if (SYMBOL_INLINE_P(sym)) {
+ mrb_value str = mrb_str_new(mrb, name, len);
+ RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+ return str;
}
return mrb_str_new_static(mrb, name, len);
}
@@ -520,13 +535,8 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym)
return name;
}
else {
- mrb_value str;
- if (sym&1) { /* inline symbol */
- str = mrb_str_new(mrb, name, len);
- }
- else {
- str = mrb_str_new_static(mrb, name, len);
- }
+ mrb_value str = SYMBOL_INLINE_P(sym) ?
+ mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len);
str = mrb_str_dump(mrb, str);
return RSTRING_PTR(str);
}
diff --git a/src/variable.c b/src/variable.c
index 23d900b7d..06756a69f 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -446,7 +446,7 @@ MRB_API void
mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name)
{
if (!mrb_iv_name_sym_p(mrb, iv_name)) {
- mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name));
+ mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name);
}
}
@@ -521,11 +521,11 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
MRB_API mrb_value
mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
{
- mrb_check_frozen(mrb, mrb_obj_ptr(obj));
if (obj_iv_p(obj)) {
iv_tbl *t = mrb_obj_ptr(obj)->iv;
mrb_value val;
+ mrb_check_frozen(mrb, mrb_obj_ptr(obj));
if (iv_del(mrb, t, sym, &val)) {
return val;
}
@@ -654,8 +654,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
if (given) return v;
}
}
- mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
- mrb_sym2str(mrb, sym), mrb_obj_value(cls));
+ mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls);
/* not reached */
return mrb_nil_value();
}
@@ -883,7 +882,15 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
if (len >= 1 && ISUPPER(s[0])) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ mrb_int i, alen = RARRAY_LEN(ary);
+
+ for (i=0; i<alen; i++) {
+ if (mrb_symbol(RARRAY_PTR(ary)[i]) == sym)
+ break;
+ }
+ if (i==alen) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
+ }
}
return 0;
}
diff --git a/src/vm.c b/src/vm.c
index 0a6d4af8d..8d233f291 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -461,7 +461,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
stack_init(mrb);
}
if (argc < 0) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc));
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%i)", argc);
}
c = mrb_class(mrb, self);
m = mrb_method_search_vm(mrb, &c, mid);
@@ -836,8 +836,8 @@ break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
struct RBreak *brk;
brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
- brk->proc = p;
- brk->val = val;
+ mrb_break_proc_set(brk, p);
+ mrb_break_value_set(brk, val);
return brk;
}
@@ -878,13 +878,11 @@ argnum_error(mrb_state *mrb, mrb_int num)
}
}
if (mrb->c->ci->mid) {
- str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
- mrb_sym2str(mrb, mrb->c->ci->mid),
- mrb_fixnum_value(argc), mrb_fixnum_value(num));
+ str = mrb_format(mrb, "'%n': wrong number of arguments (%i for %i)",
+ mrb->c->ci->mid, argc, num);
}
else {
- str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
- mrb_fixnum_value(argc), mrb_fixnum_value(num));
+ str = mrb_format(mrb, "wrong number of arguments (%i for %i)", argc, num);
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
mrb_exc_set(mrb, exc);
@@ -973,10 +971,10 @@ check_target_class(mrb_state *mrb)
void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
MRB_API mrb_value
-mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
+mrb_vm_exec(mrb_state *mrb, struct RProc *proc, const mrb_code *pc)
{
/* mrb_assert(MRB_PROC_CFUNC_P(proc)) */
- mrb_code *pc0 = pc;
+ const mrb_code *pc0 = pc;
mrb_irep *irep = proc->body.irep;
mrb_value *pool = irep->pool;
mrb_sym *syms = irep->syms;
@@ -1868,7 +1866,7 @@ RETRY_TRY_BLOCK:
mrb_value kdict = regs[mrb->c->ci->argc];
if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) {
- mrb_value str = mrb_format(mrb, "missing keyword: %S", k);
+ mrb_value str = mrb_format(mrb, "missing keyword: %v", k);
mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
goto L_RAISE;
}
@@ -1895,7 +1893,7 @@ RETRY_TRY_BLOCK:
if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) {
mrb_value keys = mrb_hash_keys(mrb, kdict);
mrb_value key1 = RARRAY_PTR(keys)[0];
- mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1);
+ mrb_value str = mrb_format(mrb, "unknown keyword: %v", key1);
mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
goto L_RAISE;
}
@@ -2102,8 +2100,8 @@ RETRY_TRY_BLOCK:
}
if (FALSE) {
L_BREAK:
- v = ((struct RBreak*)mrb->exc)->val;
- proc = ((struct RBreak*)mrb->exc)->proc;
+ v = mrb_break_value_get((struct RBreak*)mrb->exc);
+ proc = mrb_break_proc_get((struct RBreak*)mrb->exc);
mrb->exc = NULL;
ci = mrb->c->ci;
}
@@ -2443,7 +2441,12 @@ RETRY_TRY_BLOCK:
CASE(OP_ARYCAT, B) {
mrb_value splat = mrb_ary_splat(mrb, regs[a+1]);
- mrb_ary_concat(mrb, regs[a], splat);
+ if (mrb_nil_p(regs[a])) {
+ regs[a] = splat;
+ }
+ else {
+ mrb_ary_concat(mrb, regs[a], splat);
+ }
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2834,6 +2837,7 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
return mrb_vm_run(mrb, proc, self, stack_keep);
}
if (mrb->c->ci == mrb->c->cibase) {
+ mrb->c->ci->env = NULL;
return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);