summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c511
-rw-r--r--src/backtrace.c160
-rw-r--r--src/class.c537
-rw-r--r--src/codegen.c581
-rw-r--r--src/crc.c13
-rw-r--r--src/debug.c215
-rw-r--r--src/dump.c596
-rw-r--r--src/error.c88
-rw-r--r--src/error.h22
-rw-r--r--src/etc.c88
-rw-r--r--src/gc.c162
-rw-r--r--src/hash.c692
-rw-r--r--src/init.c2
-rw-r--r--src/kernel.c205
-rw-r--r--src/load.c720
-rw-r--r--src/mrb_throw.h41
-rw-r--r--src/mruby_core.rake62
-rw-r--r--src/node.h208
-rw-r--r--src/numeric.c425
-rw-r--r--src/object.c72
-rw-r--r--src/opcode.h6
-rw-r--r--src/parse.y6492
-rw-r--r--src/pool.c9
-rw-r--r--src/print.c18
-rw-r--r--src/proc.c26
-rw-r--r--src/range.c50
-rw-r--r--src/re.h3
-rw-r--r--src/state.c131
-rw-r--r--src/string.c653
-rw-r--r--src/symbol.c108
-rw-r--r--src/variable.c127
-rw-r--r--src/version.c13
-rw-r--r--src/vm.c453
33 files changed, 7311 insertions, 6178 deletions
diff --git a/src/array.c b/src/array.c
index ceda884c0..eeeef23a5 100644
--- a/src/array.c
+++ b/src/array.c
@@ -4,22 +4,20 @@
** See Copyright Notice in mruby.h
*/
-#ifndef SIZE_MAX
- /* Some versions of VC++
- * has SIZE_MAX in stdint.h
- */
-# include <limits.h>
-#endif
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/string.h"
+#include "mruby/range.h"
#include "value_array.h"
#define ARY_DEFAULT_LEN 4
#define ARY_SHRINK_RATIO 5 /* must be larger than 2 */
#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
#define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
+#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
+#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
+#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED)
static inline mrb_value
ary_elt(mrb_value ary, mrb_int offset)
@@ -81,9 +79,9 @@ mrb_ary_new(mrb_state *mrb)
*
*/
static inline void
-array_copy(mrb_value *dst, const mrb_value *src, size_t size)
+array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
{
- size_t i;
+ mrb_int i;
for (i = 0; i < size; i++) {
dst[i] = src[i];
@@ -91,12 +89,29 @@ array_copy(mrb_value *dst, const mrb_value *src, size_t size)
}
mrb_value
+mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
+{
+ mrb_value ary;
+ struct RArray *a;
+
+ ary = mrb_ary_new_capa(mrb, size);
+ a = mrb_ary_ptr(ary);
+ array_copy(a->ptr, vals, size);
+ a->len = size;
+
+ return ary;
+}
+
+mrb_value
mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
{
- mrb_value arv[2];
- arv[0] = car;
- arv[1] = cdr;
- return mrb_ary_new_from_values(mrb, 2, arv);
+ struct RArray *a;
+
+ a = ary_new_capa(mrb, 2);
+ a->ptr[0] = car;
+ a->ptr[1] = cdr;
+ a->len = 2;
+ return mrb_obj_value(a);
}
static void
@@ -104,7 +119,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
{
mrb_value nil = mrb_nil_value();
- while ((int)(size--)) {
+ while (size--) {
*ptr++ = nil;
}
}
@@ -112,7 +127,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void
ary_modify(mrb_state *mrb, struct RArray *a)
{
- if (a->flags & MRB_ARY_SHARED) {
+ if (ARY_SHARED_P(a)) {
mrb_shared_array *shared = a->aux.shared;
if (shared->refcnt == 1 && a->ptr == shared->ptr) {
@@ -134,14 +149,21 @@ ary_modify(mrb_state *mrb, struct RArray *a)
a->aux.capa = a->len;
mrb_ary_decref(mrb, shared);
}
- a->flags &= ~MRB_ARY_SHARED;
+ ARY_UNSET_SHARED_FLAG(a);
}
}
+void
+mrb_ary_modify(mrb_state *mrb, struct RArray* a)
+{
+ mrb_write_barrier(mrb, (struct RBasic*)a);
+ ary_modify(mrb, a);
+}
+
static void
ary_make_shared(mrb_state *mrb, struct RArray *a)
{
- if (!(a->flags & MRB_ARY_SHARED)) {
+ if (!ARY_SHARED_P(a)) {
mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array));
shared->refcnt = 1;
@@ -153,7 +175,7 @@ ary_make_shared(mrb_state *mrb, struct RArray *a)
}
shared->len = a->len;
a->aux.shared = shared;
- a->flags |= MRB_ARY_SHARED;
+ ARY_SET_SHARED_FLAG(a);
}
}
@@ -166,13 +188,11 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
+ if (capa == 0) {
+ capa = ARY_DEFAULT_LEN;
+ }
while (capa < len) {
- if (capa == 0) {
- capa = ARY_DEFAULT_LEN;
- }
- else {
- capa *= 2;
- }
+ capa *= 2;
}
if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
@@ -211,14 +231,16 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a)
}
}
-mrb_value
+static mrb_value
mrb_ary_s_create(mrb_state *mrb, mrb_value self)
{
mrb_value *vals;
int len;
mrb_get_args(mrb, "*", &vals, &len);
- return mrb_ary_new_from_values(mrb, len, vals);
+ mrb_assert(len <= MRB_INT_MAX); /* A rare case. So choosed assert() not raise(). */
+
+ return mrb_ary_new_from_values(mrb, (mrb_int)len, vals);
}
static void
@@ -241,7 +263,7 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
}
-mrb_value
+static mrb_value
mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
{
mrb_value *ptr;
@@ -252,7 +274,7 @@ mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+static mrb_value
mrb_ary_plus(mrb_state *mrb, mrb_value self)
{
struct RArray *a1 = mrb_ary_ptr(self);
@@ -271,53 +293,6 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
return ary;
}
-/*
- * call-seq:
- * ary <=> other_ary -> -1, 0, +1 or nil
- *
- * Comparison---Returns an integer (-1, 0, or +1)
- * if this array is less than, equal to, or greater than <i>other_ary</i>.
- * Each object in each array is compared (using <=>). If any value isn't
- * equal, then that inequality is the return value. If all the
- * values found are equal, then the return is based on a
- * comparison of the array lengths. Thus, two arrays are
- * ``equal'' according to <code>Array#<=></code> if and only if they have
- * the same length and the value of each element is equal to the
- * value of the corresponding element in the other array.
- *
- * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1
- * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1
- *
- */
-mrb_value
-mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
-{
- mrb_value ary2;
- struct RArray *a1, *a2;
- mrb_value r;
- mrb_int i, len;
-
- mrb_get_args(mrb, "o", &ary2);
- if (!mrb_array_p(ary2)) return mrb_nil_value();
- a1 = RARRAY(ary1); a2 = RARRAY(ary2);
- if (a1->len == a2->len && a1->ptr == a2->ptr) return mrb_fixnum_value(0);
- else {
- mrb_sym cmp = mrb_intern2(mrb, "<=>", 3);
-
- len = RARRAY_LEN(ary1);
- if (len > RARRAY_LEN(ary2)) {
- len = RARRAY_LEN(ary2);
- }
- for (i=0; i<len; i++) {
- mrb_value v = ary_elt(ary2, i);
- r = mrb_funcall_argv(mrb, ary_elt(ary1, i), cmp, 1, &v);
- if (mrb_type(r) != MRB_TT_FIXNUM || mrb_fixnum(r) != 0) return r;
- }
- }
- len = a1->len - a2->len;
- return mrb_fixnum_value((len == 0)? 0: (len > 0)? 1: -1);
-}
-
static void
ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
{
@@ -337,7 +312,7 @@ mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
}
-mrb_value
+static mrb_value
mrb_ary_replace_m(mrb_state *mrb, mrb_value self)
{
mrb_value other;
@@ -348,7 +323,7 @@ mrb_ary_replace_m(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+static mrb_value
mrb_ary_times(mrb_state *mrb, mrb_value self)
{
struct RArray *a1 = mrb_ary_ptr(self);
@@ -375,7 +350,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
return ary;
}
-mrb_value
+static mrb_value
mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -396,7 +371,7 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+static mrb_value
mrb_ary_reverse(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self), *b;
@@ -418,22 +393,8 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self)
return ary;
}
-mrb_value
-mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
-{
- mrb_value ary;
- struct RArray *a;
-
- ary = mrb_ary_new_capa(mrb, size);
- a = mrb_ary_ptr(ary);
- array_copy(a->ptr, vals, size);
- a->len = size;
-
- return ary;
-}
-
void
-mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) /* mrb_ary_push */
+mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -444,7 +405,7 @@ mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) /* mrb_ary_push */
mrb_write_barrier(mrb, (struct RBasic*)a);
}
-mrb_value
+static mrb_value
mrb_ary_push_m(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
@@ -476,7 +437,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
mrb_value val;
if (a->len == 0) return mrb_nil_value();
- if (a->flags & MRB_ARY_SHARED) {
+ if (ARY_SHARED_P(a)) {
L_SHIFT:
val = a->ptr[0];
a->ptr++;
@@ -492,7 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
mrb_int size = a->len;
val = *ptr;
- while ((int)(--size)) {
+ while (--size) {
*ptr = *(ptr+1);
++ptr;
}
@@ -510,7 +471,7 @@ mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
{
struct RArray *a = mrb_ary_ptr(self);
- if ((a->flags & MRB_ARY_SHARED)
+ if (ARY_SHARED_P(a)
&& a->aux.shared->refcnt == 1 /* shared only referenced from this array */
&& a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ {
a->ptr--;
@@ -529,7 +490,7 @@ mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
return self;
}
-mrb_value
+static mrb_value
mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -537,7 +498,7 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
int len;
mrb_get_args(mrb, "*", &vals, &len);
- if ((a->flags & MRB_ARY_SHARED)
+ if (ARY_SHARED_P(a)
&& a->aux.shared->refcnt == 1 /* shared only referenced from this array */
&& a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
a->ptr -= len;
@@ -563,13 +524,13 @@ mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
/* range check */
if (n < 0) n += a->len;
- if (n < 0 || a->len <= (int)n) return mrb_nil_value();
+ if (n < 0 || a->len <= n) return mrb_nil_value();
return a->ptr[n];
}
void
-mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) /* rb_ary_store */
+mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -581,8 +542,8 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) /* rb_ary_s
mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - a->len));
}
}
- if (a->len <= (int)n) {
- if (a->aux.capa <= (int)n)
+ if (a->len <= n) {
+ if (a->aux.capa <= n)
ary_expand_capa(mrb, a, n + 1);
ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len);
a->len = n + 1;
@@ -629,13 +590,13 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
ary_expand_capa(mrb, a, size);
if (head > a->len) {
- ary_fill_with_nil(a->ptr + a->len, (int)(head - a->len));
+ ary_fill_with_nil(a->ptr + a->len, head - a->len);
}
else if (head < a->len) {
value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
}
- for(i = 0; i < argc; i++) {
+ for (i = 0; i < argc; i++) {
*(a->ptr + head + i) = *(argv + i);
}
@@ -644,12 +605,6 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
return ary;
}
-mrb_int
-mrb_ary_len(mrb_state *mrb, mrb_value ary)
-{
- return RARRAY_LEN(ary);
-}
-
void
mrb_ary_decref(mrb_state *mrb, mrb_shared_array *shared)
{
@@ -671,71 +626,152 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
b->len = len;
b->aux.shared = a->aux.shared;
b->aux.shared->refcnt++;
- b->flags |= MRB_ARY_SHARED;
+ ARY_SET_SHARED_FLAG(b);
return mrb_obj_value(b);
}
-mrb_value
-mrb_ary_aget(mrb_state *mrb, mrb_value self)
+static mrb_int
+aget_index(mrb_state *mrb, mrb_value index)
{
- struct RArray *a = mrb_ary_ptr(self);
- mrb_int index, len;
- mrb_value *argv;
- int size;
+ if (mrb_fixnum_p(index)) {
+ return mrb_fixnum(index);
+ }
+ else {
+ mrb_int i;
+
+ mrb_get_args(mrb, "i", &i);
+ return i;
+ }
+}
- mrb_get_args(mrb, "i*", &index, &argv, &size);
- switch(size) {
- case 0:
- return mrb_ary_ref(mrb, self, index);
+/*
+ * call-seq:
+ * ary[index] -> obj or nil
+ * ary[start, length] -> new_ary or nil
+ * ary[range] -> new_ary or nil
+ * ary.slice(index) -> obj or nil
+ * ary.slice(start, length) -> new_ary or nil
+ * ary.slice(range) -> new_ary or nil
+ *
+ * Element Reference --- Returns the element at +index+, or returns a
+ * subarray starting at the +start+ index and continuing for +length+
+ * elements, or returns a subarray specified by +range+ of indices.
+ *
+ * Negative indices count backward from the end of the array (-1 is the last
+ * element). For +start+ and +range+ cases the starting index is just before
+ * an element. Additionally, an empty array is returned when the starting
+ * index for an element range is at the end of the array.
+ *
+ * Returns +nil+ if the index (or starting index) are out of range.
+ *
+ * a = [ "a", "b", "c", "d", "e" ]
+ * a[1] => "b"
+ * a[1,2] => ["b", "c"]
+ * a[1..-2] => ["b", "c", "d"]
+ *
+ */
- case 1:
- if (mrb_type(argv[0]) != MRB_TT_FIXNUM) {
- mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum");
+static mrb_value
+mrb_ary_aget(mrb_state *mrb, mrb_value self)
+{
+ struct RArray *a = mrb_ary_ptr(self);
+ mrb_int i, len;
+ mrb_value index;
+
+ if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
+ switch (mrb_type(index)) {
+ /* a[n..m] */
+ case MRB_TT_RANGE:
+ if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) {
+ return ary_subseq(mrb, a, i, len);
+ }
+ else {
+ return mrb_nil_value();
+ }
+ case MRB_TT_FIXNUM:
+ return mrb_ary_ref(mrb, self, mrb_fixnum(index));
+ default:
+ return mrb_ary_ref(mrb, self, aget_index(mrb, index));
}
- if (index < 0) index += a->len;
- if (index < 0 || a->len < (int)index) return mrb_nil_value();
- len = mrb_fixnum(argv[0]);
- if (len < 0) return mrb_nil_value();
- if (a->len == (int)index) return mrb_ary_new(mrb);
- if (len > a->len - index) len = a->len - index;
- return ary_subseq(mrb, a, index, len);
-
- default:
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
- break;
}
- return mrb_nil_value(); /* dummy to avoid warning : not reach here */
+ i = aget_index(mrb, index);
+ if (i < 0) i += a->len;
+ if (i < 0 || a->len < i) return mrb_nil_value();
+ if (len < 0) return mrb_nil_value();
+ if (a->len == i) return mrb_ary_new(mrb);
+ if (len > a->len - i) len = a->len - i;
+
+ return ary_subseq(mrb, a, i, len);
}
-mrb_value
+/*
+ * call-seq:
+ * ary[index] = obj -> obj
+ * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil
+ * ary[range] = obj or other_ary or nil -> obj or other_ary or nil
+ *
+ * Element Assignment --- Sets the element at +index+, or replaces a subarray
+ * from the +start+ index for +length+ elements, or replaces a subarray
+ * specified by the +range+ of indices.
+ *
+ * If indices are greater than the current capacity of the array, the array
+ * grows automatically. Elements are inserted into the array at +start+ if
+ * +length+ is zero.
+ *
+ * Negative indices will count backward from the end of the array. For
+ * +start+ and +range+ cases the starting index is just before an element.
+ *
+ * An IndexError is raised if a negative index points past the beginning of
+ * the array.
+ *
+ * See also Array#push, and Array#unshift.
+ *
+ * a = Array.new
+ * a[4] = "4"; #=> [nil, nil, nil, nil, "4"]
+ * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
+ * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"]
+ * a[0, 2] = "?" #=> ["?", 2, nil, "4"]
+ * a[0..2] = "A" #=> ["A", "4"]
+ * a[-1] = "Z" #=> ["A", "Z"]
+ * a[1..-1] = nil #=> ["A", nil]
+ * a[1..-1] = [] #=> ["A"]
+ * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"]
+ * a[3, 0] = "B" #=> [1, 2, "A", "B"]
+ */
+
+static mrb_value
mrb_ary_aset(mrb_state *mrb, mrb_value self)
{
- mrb_value *argv;
- int argc;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- switch(argc) {
- case 2:
- if (!mrb_fixnum_p(argv[0])) {
- /* Should we support Range object for 1st arg ? */
- mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum for 1st argument");
- }
- mrb_ary_set(mrb, self, mrb_fixnum(argv[0]), argv[1]);
- return argv[1];
-
- case 3:
- mrb_ary_splice(mrb, self, mrb_fixnum(argv[0]), mrb_fixnum(argv[1]), argv[2]);
- return argv[2];
+ mrb_value v1, v2, v3;
+ mrb_int i, len;
- default:
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
- return mrb_nil_value();
+ if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) {
+ switch (mrb_type(v1)) {
+ /* a[n..m] = v */
+ case MRB_TT_RANGE:
+ if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) {
+ mrb_ary_splice(mrb, self, i, len, v2);
+ }
+ break;
+ /* a[n] = v */
+ case MRB_TT_FIXNUM:
+ mrb_ary_set(mrb, self, mrb_fixnum(v1), v2);
+ break;
+ default:
+ mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
+ break;
+ }
+ return v2;
}
+
+ /* a[n,m] = v */
+ mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3);
+ return v3;
}
-mrb_value
+static mrb_value
mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -746,14 +782,14 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "i", &index);
if (index < 0) index += a->len;
- if (index < 0 || a->len <= (int)index) return mrb_nil_value();
+ if (index < 0 || a->len <= index) return mrb_nil_value();
ary_modify(mrb, a);
val = a->ptr[index];
ptr = a->ptr + index;
len = a->len - index;
- while ((int)(--len)) {
+ while (--len) {
*ptr = *(ptr+1);
++ptr;
}
@@ -764,7 +800,7 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
return val;
}
-mrb_value
+static mrb_value
mrb_ary_first(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -778,13 +814,13 @@ mrb_ary_first(mrb_state *mrb, mrb_value self)
}
if (size > a->len) size = a->len;
- if (a->flags & MRB_ARY_SHARED) {
+ if (ARY_SHARED_P(a)) {
return ary_subseq(mrb, a, 0, size);
}
return mrb_ary_new_from_values(mrb, size, a->ptr);
}
-mrb_value
+static mrb_value
mrb_ary_last(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -805,13 +841,13 @@ mrb_ary_last(mrb_state *mrb, mrb_value self)
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
}
if (size > a->len) size = a->len;
- if ((a->flags & MRB_ARY_SHARED) || size > ARY_DEFAULT_LEN) {
+ if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) {
return ary_subseq(mrb, a, a->len - size, size);
}
return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size);
}
-mrb_value
+static mrb_value
mrb_ary_index_m(mrb_state *mrb, mrb_value self)
{
mrb_value obj;
@@ -826,7 +862,7 @@ mrb_ary_index_m(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
-mrb_value
+static mrb_value
mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
{
mrb_value obj;
@@ -847,6 +883,9 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v)
if (mrb_array_p(v)) {
return v;
}
+ if (mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) {
+ return mrb_funcall(mrb, v, "to_a", 0);
+ }
else {
return mrb_ary_new_from_values(mrb, 1, &v);
}
@@ -874,7 +913,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+static mrb_value
mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -885,7 +924,7 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
mrb_value
mrb_check_array_type(mrb_state *mrb, mrb_value ary)
{
- return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
+ return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
}
mrb_value
@@ -898,72 +937,13 @@ mrb_ary_entry(mrb_value ary, mrb_int offset)
}
static mrb_value
-inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
-{
- mrb_int i;
- mrb_value s, arystr;
- char head[] = { '[' };
- char sep[] = { ',', ' ' };
- char tail[] = { ']' };
-
- /* check recursive */
- for(i=0; i<RARRAY_LEN(list); i++) {
- if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
- return mrb_str_new(mrb, "[...]", 5);
- }
- }
-
- mrb_ary_push(mrb, list, ary);
-
- arystr = mrb_str_buf_new(mrb, 64);
- mrb_str_buf_cat(mrb, arystr, head, sizeof(head));
-
- for(i=0; i<RARRAY_LEN(ary); i++) {
- int ai = mrb_gc_arena_save(mrb);
-
- if (i > 0) {
- mrb_str_buf_cat(mrb, arystr, sep, sizeof(sep));
- }
- if (mrb_array_p(RARRAY_PTR(ary)[i])) {
- s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list);
- }
- else {
- s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]);
- }
- mrb_str_buf_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
- mrb_gc_arena_restore(mrb, ai);
- }
-
- mrb_str_buf_cat(mrb, arystr, tail, sizeof(tail));
- mrb_ary_pop(mrb, list);
-
- return arystr;
-}
-
-/* 15.2.12.5.31 (x) */
-/*
- * call-seq:
- * ary.to_s -> string
- * ary.inspect -> string
- *
- * Creates a string representation of +self+.
- */
-
-static mrb_value
-mrb_ary_inspect(mrb_state *mrb, mrb_value ary)
-{
- if (RARRAY_LEN(ary) == 0) return mrb_str_new(mrb, "[]", 2);
- return inspect_ary(mrb, ary, mrb_ary_new(mrb));
-}
-
-static mrb_value
join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
{
mrb_int i;
mrb_value result, val, tmp;
/* check recursive */
- for(i=0; i<RARRAY_LEN(list); i++) {
+ for (i=0; i<RARRAY_LEN(list); i++) {
if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join");
}
@@ -973,13 +953,13 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
result = mrb_str_buf_new(mrb, 64);
- for(i=0; i<RARRAY_LEN(ary); i++) {
+ for (i=0; i<RARRAY_LEN(ary); i++) {
if (i > 0 && !mrb_nil_p(sep)) {
mrb_str_buf_cat(mrb, result, RSTRING_PTR(sep), RSTRING_LEN(sep));
}
val = RARRAY_PTR(ary)[i];
- switch(mrb_type(val)) {
+ switch (mrb_type(val)) {
case MRB_TT_ARRAY:
ary_join:
val = join_ary(mrb, val, sep, list);
@@ -1038,72 +1018,35 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary)
return mrb_ary_join(mrb, ary, sep);
}
-/* 15.2.12.5.33 (x) */
-/*
- * call-seq:
- * ary == other_ary -> bool
- *
- * Equality---Two arrays are equal if they contain the same number
- * of elements and if each element is equal to (according to
- * Object.==) the corresponding element in the other array.
- *
- * [ "a", "c" ] == [ "a", "c", 7 ] #=> false
- * [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true
- * [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false
- *
- */
-
static mrb_value
-mrb_ary_equal(mrb_state *mrb, mrb_value ary1)
+mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
{
mrb_value ary2;
- mrb_int i;
mrb_get_args(mrb, "o", &ary2);
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
if (mrb_special_const_p(ary2)) return mrb_false_value();
if (!mrb_array_p(ary2)) {
- if (!mrb_respond_to(mrb, ary2, mrb_intern2(mrb, "to_ary", 6))) {
- return mrb_false_value();
- }
- else {
- return mrb_bool_value(mrb_equal(mrb, ary2, ary1));
- }
+ return mrb_false_value();
}
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value();
- for (i=0; i<RARRAY_LEN(ary1); i++) {
- if (!mrb_equal(mrb, ary_elt(ary1, i), ary_elt(ary2, i))) {
- return mrb_false_value();
- }
- }
- return mrb_true_value();
-}
-/* 15.2.12.5.34 (x) */
-/*
- * call-seq:
- * ary.eql?(other) -> true or false
- *
- * Returns <code>true</code> if +self+ and _other_ are the same object,
- * or are both arrays with the same content.
- */
+ return ary2;
+}
static mrb_value
-mrb_ary_eql(mrb_state *mrb, mrb_value ary1)
+mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
{
mrb_value ary2;
- mrb_int i;
mrb_get_args(mrb, "o", &ary2);
- if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
- if (!mrb_array_p(ary2)) return mrb_false_value();
- if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value();
- for (i=0; i<RARRAY_LEN(ary1); i++) {
- if (!mrb_eql(mrb, ary_elt(ary1, i), ary_elt(ary2, i))) {
- return mrb_false_value();
- }
+ if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0);
+ if (mrb_special_const_p(ary2)) return mrb_nil_value();
+ if (!mrb_array_p(ary2)) {
+ return mrb_nil_value();
}
- return mrb_true_value();
+
+ return ary2;
}
void
@@ -1113,12 +1056,11 @@ mrb_init_array(mrb_state *mrb)
a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
- mrb_include_module(mrb, a, mrb_class_get(mrb, "Enumerable"));
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_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
- mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
+ 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 */
@@ -1143,9 +1085,6 @@ mrb_init_array(mrb_state *mrb)
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_method(mrb, a, "inspect", mrb_ary_inspect, MRB_ARGS_NONE()); /* 15.2.12.5.31 (x) */
- mrb_define_alias(mrb, a, "to_s", "inspect"); /* 15.2.12.5.32 (x) */
- mrb_define_method(mrb, a, "==", mrb_ary_equal, MRB_ARGS_REQ(1)); /* 15.2.12.5.33 (x) */
- mrb_define_method(mrb, a, "eql?", mrb_ary_eql, MRB_ARGS_REQ(1)); /* 15.2.12.5.34 (x) */
- mrb_define_method(mrb, a, "<=>", mrb_ary_cmp, MRB_ARGS_REQ(1)); /* 15.2.12.5.36 (x) */
+ 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));
}
diff --git a/src/backtrace.c b/src/backtrace.c
index e05ad4326..c18a7cb95 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -4,70 +4,176 @@
** See Copyright Notice in mruby.h
*/
+#include <stdarg.h>
#include "mruby.h"
#include "mruby/variable.h"
#include "mruby/proc.h"
+#include "mruby/array.h"
+#include "mruby/string.h"
+#include "mruby/class.h"
+#include "mruby/debug.h"
+#include "mruby/error.h"
+
+typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...);
-void
-mrb_print_backtrace(mrb_state *mrb)
-{
#ifdef ENABLE_STDIO
+static void
+print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf((FILE*)stream, format, ap);
+ va_end(ap);
+}
+#endif
+
+#define MIN_BUFSIZE 127
+
+static void
+get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...)
+{
+ va_list ap;
+ mrb_value ary, str;
+ int ai;
+
+ if (level > 0) {
+ return;
+ }
+
+ ai = mrb_gc_arena_save(mrb);
+ ary = mrb_obj_value((struct RArray*)stream);
+
+ va_start(ap, format);
+ str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1);
+ va_end(ap);
+
+ va_start(ap, format);
+ vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap);
+ va_end(ap);
+
+ mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1);
+ mrb_ary_push(mrb, ary, str);
+ mrb_gc_arena_restore(mrb, ai);
+}
+
+static void
+output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream)
+{
mrb_callinfo *ci;
- mrb_int ciidx;
const char *filename, *method, *sep;
- int i, line;
+ int i, lineno, tracehead = 1;
- fputs("trace:\n", stderr);
- ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern2(mrb, "ciidx", 5)));
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
for (i = ciidx; i >= 0; i--) {
ci = &mrb->c->cibase[i];
- filename = "(unknown)";
- line = -1;
+ filename = NULL;
+ lineno = -1;
+ if (!ci->proc) continue;
if (MRB_PROC_CFUNC_P(ci->proc)) {
continue;
}
else {
mrb_irep *irep = ci->proc->body.irep;
- if (irep->filename != NULL)
- filename = irep->filename;
- if (irep->lines != NULL) {
- mrb_code *pc;
-
- if (i+1 <= ciidx) {
- pc = mrb->c->cibase[i+1].pc;
- }
- else {
- pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern2(mrb, "lastpc", 6)));
- }
- if (irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
- line = irep->lines[pc - irep->iseq - 1];
- }
+ mrb_code *pc;
+
+ if (mrb->c->cibase[i].err) {
+ pc = mrb->c->cibase[i].err;
+ }
+ else if (i+1 <= ciidx) {
+ pc = mrb->c->cibase[i+1].pc - 1;
+ }
+ else {
+ pc = pc0;
}
+ filename = mrb_debug_get_filename(irep, pc - irep->iseq);
+ lineno = mrb_debug_get_line(irep, pc - irep->iseq);
}
- if (line == -1) continue;
+ if (lineno == -1) continue;
if (ci->target_class == ci->proc->target_class)
sep = ".";
else
sep = "#";
+ if (!filename) {
+ filename = "(unknown)";
+ }
+
+ if (tracehead) {
+ func(mrb, stream, 1, "trace:\n");
+ tracehead = 0;
+ }
method = mrb_sym2name(mrb, ci->mid);
if (method) {
const char *cn = mrb_class_name(mrb, ci->proc->target_class);
if (cn) {
- fprintf(stderr, "\t[%d] %s:%d:in %s%s%s\n", i, filename, line, cn, sep, method);
+ func(mrb, stream, 1, "\t[%d] ", i);
+ func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method);
+ func(mrb, stream, 1, "\n");
}
else {
- fprintf(stderr, "\t[%d] %s:%d:in %s\n", i, filename, line, method);
+ func(mrb, stream, 1, "\t[%d] ", i);
+ func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method);
+ func(mrb, stream, 1, "\n");
}
}
else {
- fprintf(stderr, "\t[%d] %s:%d\n", i, filename, line);
+ func(mrb, stream, 1, "\t[%d] ", i);
+ func(mrb, stream, 0, "%s:%d", filename, lineno);
+ func(mrb, stream, 1, "\n");
}
}
+}
+
+static void
+exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
+{
+ output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))),
+ (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))),
+ func, stream);
+}
+
+/* mrb_print_backtrace/mrb_get_backtrace:
+
+ function to retrieve backtrace information from the exception.
+ note that if you call method after the exception, call stack will be
+ overwritten. So invoke these functions just after detecting exceptions.
+*/
+
+void
+mrb_print_backtrace(mrb_state *mrb)
+{
+#ifdef ENABLE_STDIO
+ exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr);
#endif
}
+
+mrb_value
+mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
+{
+ mrb_value ary;
+
+ ary = mrb_ary_new(mrb);
+ exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary));
+
+ return ary;
+}
+
+mrb_value
+mrb_get_backtrace(mrb_state *mrb)
+{
+ mrb_value ary;
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_code *pc = ci->pc;
+ mrb_int ciidx = ci - mrb->c->cibase - 1;
+
+ if (ciidx < 0) ciidx = 0;
+ ary = mrb_ary_new(mrb);
+ output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary));
+
+ return ary;
+}
diff --git a/src/class.c b/src/class.c
index 4994b0045..33515de2c 100644
--- a/src/class.c
+++ b/src/class.c
@@ -4,18 +4,19 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include <stdarg.h>
#include <ctype.h>
+#include <stdarg.h>
+#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/numeric.h"
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/variable.h"
-#include "error.h"
+#include "mruby/error.h"
+#include "mruby/data.h"
-KHASH_DEFINE(mt, mrb_sym, struct RProc*, 1, kh_int_hash_func, kh_int_hash_equal)
+KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
void
mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
@@ -46,16 +47,27 @@ mrb_gc_mark_mt_size(mrb_state *mrb, struct RClass *c)
void
mrb_gc_free_mt(mrb_state *mrb, struct RClass *c)
{
- kh_destroy(mt, c->mt);
+ kh_destroy(mt, mrb, c->mt);
}
-void
-mrb_name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
+static void
+name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
{
mrb_obj_iv_set(mrb, (struct RObject*)c,
- mrb_intern2(mrb, "__classid__", 11), mrb_symbol_value(name));
+ mrb_intern_lit(mrb, "__classid__"), mrb_symbol_value(name));
+}
+
+static void
+setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
+{
+ name_class(mrb, c, id);
+ mrb_obj_iv_set(mrb, (struct RObject*)outer, id, mrb_obj_value(c));
+ if (outer != mrb->object_class) {
+ mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
+ mrb_obj_value(outer));
+ }
}
-
+
#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))
static void
@@ -89,34 +101,25 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
o->c = sc;
mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
- mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern2(mrb, "__attached__", 12), mrb_obj_value(o));
+ mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o));
}
-struct RClass*
-mrb_define_module_id(mrb_state *mrb, mrb_sym name)
+static struct RClass *
+class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
{
- struct RClass *m = mrb_module_new(mrb);
-
- mrb_obj_iv_set(mrb, (struct RObject*)mrb->object_class,
- name, mrb_obj_value(m));
- mrb_name_class(mrb, m, name);
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
- return m;
+ mrb_check_type(mrb, c, MRB_TT_CLASS);
+ return mrb_class_ptr(c);
}
-struct RClass*
-mrb_define_module(mrb_state *mrb, const char *name)
+static struct RClass *
+module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
{
- return mrb_define_module_id(mrb, mrb_intern_cstr(mrb, name));
-}
+ mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
-static void
-setup_class(mrb_state *mrb, mrb_value outer, struct RClass *c, mrb_sym id)
-{
- mrb_name_class(mrb, c, id);
- mrb_const_set(mrb, outer, id, mrb_obj_value(c));
- mrb_obj_iv_set(mrb, (struct RObject*)c,
- mrb_intern2(mrb, "__outer__", 9), outer);
+ mrb_check_type(mrb, c, MRB_TT_MODULE);
+ return mrb_class_ptr(c);
}
struct RClass*
@@ -124,41 +127,84 @@ mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
{
mrb_value outer;
- outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern2(mrb, "__outer__", 9));
+ outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
if (mrb_nil_p(outer)) return 0;
return mrb_class_ptr(outer);
}
+static struct RClass*
+define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer)
+{
+ struct RClass *m;
+
+ if (mrb_const_defined_at(mrb, outer, name)) {
+ return module_from_sym(mrb, outer, name);
+ }
+ m = mrb_module_new(mrb);
+ setup_class(mrb, outer, m, name);
+
+ return m;
+}
+
+struct RClass*
+mrb_define_module_id(mrb_state *mrb, mrb_sym name)
+{
+ return define_module(mrb, name, mrb->object_class);
+}
+
+struct RClass*
+mrb_define_module(mrb_state *mrb, const char *name)
+{
+ return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class);
+}
+
struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
- struct RClass *c;
- mrb_value v;
+ return define_module(mrb, id, mrb_class_ptr(outer));
+}
- if (mrb_const_defined(mrb, outer, id)) {
- v = mrb_const_get(mrb, outer, id);
- c = mrb_class_ptr(v);
- }
- else {
- c = mrb_module_new(mrb);
- setup_class(mrb, outer, c, id);
- }
+struct RClass *
+mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
+{
+ mrb_sym id = mrb_intern_cstr(mrb, name);
+ struct RClass * c = define_module(mrb, id, outer);
+
+ setup_class(mrb, outer, c, id);
return c;
}
-struct RClass*
-mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super)
+static struct RClass*
+define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer)
{
- struct RClass *c = mrb_class_new(mrb, super);
+ struct RClass * c;
+
+ if (mrb_const_defined_at(mrb, outer, name)) {
+ c = class_from_sym(mrb, outer, name);
+ 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));
+ }
+ return c;
+ }
- mrb_obj_iv_set(mrb, (struct RObject*)mrb->object_class,
- name, mrb_obj_value(c));
- mrb_name_class(mrb, c, name);
+ c = mrb_class_new(mrb, super);
+ setup_class(mrb, outer, c, name);
return c;
}
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));
+ }
+ return define_class(mrb, name, super, mrb->object_class);
+}
+
+struct RClass*
mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
{
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
@@ -167,24 +213,8 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
- struct RClass *c, *s;
-
- if (mrb_const_defined(mrb, outer, id)) {
- mrb_value v = mrb_const_get(mrb, outer, id);
-
- mrb_check_type(mrb, v, MRB_TT_CLASS);
- c = mrb_class_ptr(v);
- 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)", super);
- }
-
- if (!c->super || mrb_class_ptr(super) != mrb_class_real(c->super)) {
- mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", mrb_sym2str(mrb, id));
- }
- }
- return c;
- }
+ struct RClass *s;
+ struct RClass *c;
if (!mrb_nil_p(super)) {
if (mrb_type(super) != MRB_TT_CLASS) {
@@ -193,12 +223,18 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
s = mrb_class_ptr(super);
}
else {
- s = mrb->object_class;
+ s = 0;
}
-
- c = mrb_class_new(mrb, s);
- setup_class(mrb, outer, c, id);
- mrb_funcall(mrb, mrb_obj_value(s), "inherited", 1, mrb_obj_value(c));
+ switch (mrb_type(outer)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", outer);
+ break;
+ }
+ c = define_class(mrb, id, s, mrb_class_ptr(outer));
+ mrb_funcall(mrb, mrb_obj_value(mrb_class_real(c->super)), "inherited", 1, mrb_obj_value(c));
return c;
}
@@ -213,15 +249,10 @@ mrb_class_defined(mrb_state *mrb, const char *name)
return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym));
}
-static struct RClass *
-class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
+struct RClass *
+mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
- mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
-
- if (mrb_type(c) != MRB_TT_MODULE && mrb_type(c) != MRB_TT_CLASS) {
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_sym2str(mrb, id));
- }
- return mrb_class_ptr(c);
+ return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
}
struct RClass *
@@ -231,9 +262,15 @@ mrb_class_get(mrb_state *mrb, const char *name)
}
struct RClass *
-mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
+mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
- return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
+ return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
+}
+
+struct RClass *
+mrb_module_get(mrb_state *mrb, const char *name)
+{
+ return mrb_module_get_under(mrb, mrb->object_class, name);
}
/*!
@@ -255,38 +292,17 @@ mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
struct RClass *
mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
{
- struct RClass * c;
mrb_sym id = mrb_intern_cstr(mrb, name);
-
- if (mrb_const_defined_at(mrb, outer, id)) {
- c = class_from_sym(mrb, outer, id);
- if (mrb_class_real(c->super) != super) {
- mrb_name_error(mrb, id, "%S is already defined", name);
- }
- return c;
- }
- if (!super) {
- mrb_warn(mrb, "no super class for `%S::%S', Object assumed", outer, name);
- }
- c = mrb_class_new(mrb, super);
- setup_class(mrb, mrb_obj_value(outer), c, id);
-
- return c;
-}
-
-struct RClass *
-mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
-{
struct RClass * c;
- mrb_sym id = mrb_intern_cstr(mrb, name);
- if (mrb_const_defined_at(mrb, outer, id)) {
- c = class_from_sym(mrb, outer, id);
- return c;
+#if 0
+ if (!super) {
+ mrb_warn(mrb, "no super class for `%S::%S', Object assumed",
+ mrb_obj_value(outer), mrb_sym2str(mrb, id));
}
- c = mrb_module_new(mrb);
- setup_class(mrb, mrb_obj_value(outer), c, id);
-
+#endif
+ c = define_class(mrb, id, super, outer);
+ setup_class(mrb, outer, c, id);
return c;
}
@@ -297,7 +313,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
khiter_t k;
if (!h) h = c->mt = kh_init(mt, mrb);
- k = kh_put(mt, h, mid);
+ k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
if (p) {
mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
@@ -311,6 +327,7 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f
int ai = mrb_gc_arena_save(mrb);
p = mrb_proc_new_cfunc(mrb, func);
+ p->target_class = c;
mrb_define_method_raw(mrb, c, mid, p);
mrb_gc_arena_restore(mrb, ai);
}
@@ -329,7 +346,7 @@ mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value b
struct RProc *p;
if (!h) h = c->mt = kh_init(mt, mrb);
- k = kh_put(mt, h, name);
+ k = kh_put(mt, mrb, h, name);
p = mrb_proc_ptr(body);
kh_value(h, k) = p;
if (p) {
@@ -379,6 +396,7 @@ to_hash(mrb_state *mrb, mrb_value val)
string mruby type C type note
----------------------------------------------------------------------------------------------
o: Object [mrb_value]
+ C: class/module [mrb_value]
S: String [mrb_value]
A: Array [mrb_value]
H: Hash [mrb_value]
@@ -389,9 +407,11 @@ to_hash(mrb_state *mrb, mrb_value val)
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
&: Block [mrb_value]
*: rest argument [mrb_value*,int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
+ ?: optional given [mrb_bool] true if preceding argument (optional) is given.
*/
int
mrb_get_args(mrb_state *mrb, const char *format, ...)
@@ -401,7 +421,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *sp = mrb->c->stack + 1;
va_list ap;
int argc = mrb->c->ci->argc;
- int opt = 0;
+ mrb_bool opt = 0;
+ mrb_bool given = 1;
va_start(ap, format);
if (argc < 0) {
@@ -412,11 +433,16 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
while ((c = *format++)) {
switch (c) {
- case '|': case '*': case '&':
+ case '|': case '*': case '&': case '?':
break;
default:
- if (argc <= i && !opt) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ if (argc <= i) {
+ if (opt) {
+ given = 0;
+ }
+ else {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
+ }
}
break;
}
@@ -433,6 +459,29 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ case 'C':
+ {
+ mrb_value *p;
+
+ p = va_arg(ap, mrb_value*);
+ if (i < argc) {
+ mrb_value ss;
+
+ ss = *sp++;
+ switch (mrb_type(ss)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_SCLASS:
+ break;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
+ break;
+ }
+ *p = ss;
+ i++;
+ }
+ }
+ break;
case 'S':
{
mrb_value *p;
@@ -469,7 +518,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 's':
{
mrb_value ss;
- struct RString *s;
char **ps = 0;
int *pl = 0;
@@ -477,9 +525,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pl = va_arg(ap, int*);
if (i < argc) {
ss = to_str(mrb, *sp++);
- s = mrb_str_ptr(ss);
- *ps = s->ptr;
- *pl = s->len;
+ *ps = RSTRING_PTR(ss);
+ *pl = RSTRING_LEN(ss);
i++;
}
}
@@ -487,17 +534,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 'z':
{
mrb_value ss;
- struct RString *s;
char **ps;
ps = va_arg(ap, char**);
if (i < argc) {
ss = to_str(mrb, *sp++);
- s = mrb_str_ptr(ss);
- if (strlen(s->ptr) < s->len) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL");
- }
- *ps = s->ptr;
+ *ps = mrb_string_value_cstr(mrb, &ss);
i++;
}
}
@@ -526,25 +568,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_float*);
if (i < argc) {
- switch (mrb_type(*sp)) {
- case MRB_TT_FLOAT:
- *p = mrb_float(*sp);
- break;
- case MRB_TT_FIXNUM:
- *p = (mrb_float)mrb_fixnum(*sp);
- break;
- case MRB_TT_STRING:
- mrb_raise(mrb, E_TYPE_ERROR, "String can't be coerced into Float");
- break;
- default:
- {
- mrb_value tmp;
-
- tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f");
- *p = mrb_float(tmp);
- }
- break;
- }
+ *p = mrb_to_flo(mrb, *sp);
sp++;
i++;
}
@@ -570,16 +594,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
*p = (mrb_int)f;
}
break;
- case MRB_TT_FALSE:
- *p = 0;
+ case MRB_TT_STRING:
+ mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer");
break;
default:
- {
- mrb_value tmp;
-
- tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int");
- *p = mrb_fixnum(tmp);
- }
+ *p = mrb_fixnum(mrb_Integer(mrb, *sp));
break;
}
sp++;
@@ -621,6 +640,19 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
+ case 'd':
+ {
+ void** datap;
+ struct mrb_data_type const* type;
+
+ datap = va_arg(ap, void**);
+ type = va_arg(ap, struct mrb_data_type const*);
+ if (i < argc) {
+ *datap = mrb_data_get_ptr(mrb, *sp++, type);
+ ++i;
+ }
+ }
+ break;
case '&':
{
@@ -639,6 +671,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case '|':
opt = 1;
break;
+ case '?':
+ {
+ mrb_bool *p;
+
+ p = va_arg(ap, mrb_bool*);
+ *p = given;
+ }
+ break;
case '*':
{
@@ -679,8 +719,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
struct RClass *c;
c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
- c->super = super ? super : mrb->object_class;
- mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
+ if (super) {
+ c->super = super;
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
+ }
+ else {
+ c->super = mrb->object_class;
+ }
c->mt = kh_init(mt, mrb);
return c;
}
@@ -734,7 +779,7 @@ mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
mrb_value klass;
mrb_check_type(mrb, mod, MRB_TT_MODULE);
- mrb_get_args(mrb, "o", &klass);
+ mrb_get_args(mrb, "C", &klass);
mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
return mod;
}
@@ -782,7 +827,7 @@ mrb_mod_include_p(mrb_state *mrb, mrb_value mod)
mrb_value mod2;
struct RClass *c = mrb_class_ptr(mod);
- mrb_get_args(mrb, "o", &mod2);
+ mrb_get_args(mrb, "C", &mod2);
mrb_check_type(mrb, mod2, MRB_TT_MODULE);
while (c) {
@@ -844,7 +889,7 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
return result;
}
-mrb_value class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
+mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
/* 15.2.2.4.33 */
/*
@@ -880,11 +925,9 @@ mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
struct RClass *c = mrb_class_ptr(mod);
mrb_bool recur = TRUE;
mrb_get_args(mrb, "|b", &recur);
- return class_instance_method_list(mrb, recur, c, 0);
+ return mrb_class_instance_method_list(mrb, recur, c, 0);
}
-mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c);
-
/* 15.2.2.4.35 */
/*
* call-seq:
@@ -906,7 +949,7 @@ mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
}
c = mrb_class_ptr(mod);
- return mrb_yield_internal(mrb, b, 0, 0, mod, c);
+ return mrb_yield_with_class(mrb, b, 0, 0, mod, c);
}
mrb_value
@@ -927,7 +970,7 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
return mrb_obj_value(mrb->false_class);
case MRB_TT_TRUE:
return mrb_obj_value(mrb->true_class);
- case MRB_TT_VOIDP:
+ case MRB_TT_CPTR:
return mrb_obj_value(mrb->object_class);
case MRB_TT_SYMBOL:
case MRB_TT_FIXNUM:
@@ -939,6 +982,10 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
}
obj = mrb_basic_ptr(v);
prepare_singleton_class(mrb, obj);
+ if (mrb->c && mrb->c->ci && mrb->c->ci->target_class) {
+ mrb_obj_iv_set(mrb, (struct RObject*)obj->c, mrb_intern_lit(mrb, "__outer__"),
+ mrb_obj_value(mrb->c->ci->target_class));
+ }
return mrb_obj_value(obj->c);
}
@@ -973,7 +1020,7 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
khash_t(mt) *h = c->mt;
if (h) {
- k = kh_get(mt, h, mid);
+ k = kh_get(mt, mrb, h, mid);
if (k != kh_end(h)) {
m = kh_value(h, k);
if (!m) break;
@@ -1003,10 +1050,19 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
return m;
}
-void
-mrb_obj_call_init(mrb_state *mrb, mrb_value obj, int argc, mrb_value *argv)
+static mrb_value
+mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
{
- mrb_funcall_argv(mrb, obj, mrb->init_sym, argc, argv);
+ struct RClass *c = mrb_class_ptr(cv);
+ struct RObject *o;
+ enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
+
+ if (c->tt == MRB_TT_SCLASS)
+ mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
+
+ if (ttype == 0) ttype = MRB_TT_OBJECT;
+ o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
+ return mrb_obj_value(o);
}
/*
@@ -1020,70 +1076,47 @@ mrb_obj_call_init(mrb_state *mrb, mrb_value obj, int argc, mrb_value *argv)
* an object is constructed using .new.
*
*/
-mrb_value
-mrb_class_new_instance(mrb_state *mrb, int argc, mrb_value *argv, struct RClass * klass)
-{
- mrb_value obj;
- struct RClass * c = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, klass);
- c->super = klass;
- obj = mrb_obj_value(c);
- mrb_obj_call_init(mrb, obj, argc, argv);
- return obj;
-}
mrb_value
-mrb_class_new_instance_m(mrb_state *mrb, mrb_value klass)
+mrb_instance_new(mrb_state *mrb, mrb_value cv)
{
+ mrb_value obj, blk;
mrb_value *argv;
- mrb_value blk;
- struct RClass *k = mrb_class_ptr(klass);
- struct RClass *c;
int argc;
- mrb_value obj;
+ obj = mrb_instance_alloc(mrb, cv);
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
- c = (struct RClass*)mrb_obj_alloc(mrb, k->tt, k);
- c->super = k;
- obj = mrb_obj_value(c);
- mrb_funcall_with_block(mrb, obj, mrb->init_sym, argc, argv, blk);
+ mrb_funcall_with_block(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv, blk);
return obj;
}
mrb_value
-mrb_instance_new(mrb_state *mrb, mrb_value cv)
+mrb_obj_new(mrb_state *mrb, struct RClass *c, int argc, const mrb_value *argv)
{
- struct RClass *c = mrb_class_ptr(cv);
- struct RObject *o;
- enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
- mrb_value obj, blk;
- mrb_value *argv;
- int argc;
-
- if (c->tt == MRB_TT_SCLASS)
- mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
+ mrb_value obj;
- if (ttype == 0) ttype = MRB_TT_OBJECT;
- o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
- obj = mrb_obj_value(o);
- mrb_get_args(mrb, "*&", &argv, &argc, &blk);
- mrb_funcall_with_block(mrb, obj, mrb->init_sym, argc, argv, blk);
+ obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
+ mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv);
return obj;
}
-mrb_value
+static mrb_value
mrb_class_new_class(mrb_state *mrb, mrb_value cv)
{
- mrb_value super;
- struct RClass *new_class;
+ mrb_value super, blk;
+ mrb_value new_class;
- if (mrb_get_args(mrb, "|o", &super) == 0) {
+ if (mrb_get_args(mrb, "|C&", &super, &blk) == 0) {
super = mrb_obj_value(mrb->object_class);
}
- new_class = mrb_class_new(mrb, mrb_class_ptr(super));
- mrb_funcall(mrb, super, "inherited", 1, mrb_obj_value(new_class));
- return mrb_obj_value(new_class);
+ new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
+ if (!mrb_nil_p(blk)) {
+ mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "class_eval"), 0, NULL, blk);
+ }
+ mrb_funcall(mrb, super, "inherited", 1, new_class);
+ return new_class;
}
mrb_value
@@ -1151,28 +1184,34 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
mrb_sym name;
mrb_value *a;
int alen;
- mrb_value inspect;
+ mrb_sym inspect;
+ mrb_value repr;
mrb_get_args(mrb, "n*", &name, &a, &alen);
- if (mrb_respond_to(mrb,mod,mrb_intern2(mrb, "inspect",7))){
- inspect = mrb_funcall(mrb, mod, "inspect", 0);
- if (RSTRING_LEN(inspect) > 64) {
- inspect = mrb_any_to_s(mrb, mod);
+ inspect = mrb_intern_lit(mrb, "inspect");
+ if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
+ /* method missing in inspect; avoid recursion */
+ repr = mrb_any_to_s(mrb, mod);
+ }
+ else if (mrb_respond_to(mrb, mod, inspect)) {
+ repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0);
+ if (RSTRING_LEN(repr) > 64) {
+ repr = mrb_any_to_s(mrb, mod);
}
}
else {
- inspect = mrb_any_to_s(mrb, mod);
+ repr = mrb_any_to_s(mrb, mod);
}
mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), inspect);
+ mrb_sym2str(mrb, name), repr);
/* not reached */
return mrb_nil_value();
}
mrb_bool
-mrb_obj_respond_to(struct RClass* c, mrb_sym mid)
+mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
{
khiter_t k;
@@ -1180,7 +1219,7 @@ mrb_obj_respond_to(struct RClass* c, mrb_sym mid)
khash_t(mt) *h = c->mt;
if (h) {
- k = kh_get(mt, h, mid);
+ k = kh_get(mt, mrb, h, mid);
if (k != kh_end(h)) {
if (kh_value(h, k)) {
return TRUE; /* method exists */
@@ -1198,7 +1237,7 @@ mrb_obj_respond_to(struct RClass* c, mrb_sym mid)
mrb_bool
mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid)
{
- return mrb_obj_respond_to(mrb_class(mrb, obj), mid);
+ return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid);
}
mrb_value
@@ -1206,8 +1245,8 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
{
mrb_value path;
const char *name;
- size_t len;
- mrb_sym classpath = mrb_intern2(mrb, "__classpath__", 13);
+ mrb_int len;
+ mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__");
path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath);
if (mrb_nil_p(path)) {
@@ -1218,7 +1257,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
}
else if (outer && outer != mrb->object_class) {
mrb_value base = mrb_class_path(mrb, outer);
- path = mrb_str_plus(mrb, base, mrb_str_new(mrb, "::", 2));
+ path = mrb_str_plus(mrb, base, mrb_str_new_lit(mrb, "::"));
name = mrb_sym2name_len(mrb, sym, &len);
mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len));
}
@@ -1245,11 +1284,11 @@ mrb_class_name(mrb_state *mrb, struct RClass* c)
{
mrb_value path = mrb_class_path(mrb, c);
if (mrb_nil_p(path)) {
- path = mrb_str_new(mrb, "#<Class:", 8);
+ path = mrb_str_new_lit(mrb, "#<Class:");
mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
- mrb_str_cat(mrb, path, ">", 1);
+ mrb_str_cat_lit(mrb, path, ">");
}
- return mrb_str_ptr(path)->ptr;
+ return RSTRING_PTR(path);
}
const char*
@@ -1368,9 +1407,9 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
mrb_value str;
if (mrb_type(klass) == MRB_TT_SCLASS) {
- mrb_value v = mrb_iv_get(mrb, klass, mrb_intern2(mrb, "__attached__", 12));
+ mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__"));
- str = mrb_str_new(mrb, "#<Class:", 8);
+ str = mrb_str_new_lit(mrb, "#<Class:");
switch (mrb_type(v)) {
case MRB_TT_CLASS:
@@ -1382,7 +1421,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
mrb_str_append(mrb, str, mrb_any_to_s(mrb, v));
break;
}
- mrb_str_cat(mrb, str, ">", 1);
+ mrb_str_cat_lit(mrb, str, ">");
}
else {
struct RClass *c;
@@ -1395,20 +1434,20 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
if (mrb_nil_p(path)) {
switch (mrb_type(klass)) {
case MRB_TT_CLASS:
- mrb_str_cat(mrb, str, "#<Class:", 8);
+ mrb_str_cat_lit(mrb, str, "#<Class:");
break;
case MRB_TT_MODULE:
- mrb_str_cat(mrb, str, "#<Module:", 9);
+ mrb_str_cat_lit(mrb, str, "#<Module:");
break;
default:
/* Shouldn't be happened? */
- mrb_str_cat(mrb, str, "#<??????:", 9);
+ mrb_str_cat_lit(mrb, str, "#<??????:");
break;
}
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
- mrb_str_cat(mrb, str, ">", 1);
+ mrb_str_cat_lit(mrb, str, ">");
}
else {
str = path;
@@ -1434,7 +1473,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
{
mrb_value m;
- if (!mrb_obj_respond_to(c, 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 {
@@ -1484,15 +1523,16 @@ mod_define_method(mrb_state *mrb, mrb_value self)
}
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
mrb_proc_copy(p, mrb_proc_ptr(blk));
+ p->flags |= MRB_PROC_STRICT;
mrb_define_method_raw(mrb, c, mid, p);
- return blk;
+ return mrb_symbol_value(mid);
}
static void
check_cv_name_sym(mrb_state *mrb, mrb_sym id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, id, &len);
if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
@@ -1504,7 +1544,8 @@ static void
check_cv_name_str(mrb_state *mrb, mrb_value str)
{
const char *s = RSTRING_PTR(str);
- size_t const len = RSTRING_LEN(str);
+ mrb_int len = RSTRING_LEN(str);
+
if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
mrb_name_error(mrb, mrb_intern_str(mrb, str), "`%S' is not allowed as a class variable name", str);
}
@@ -1704,7 +1745,7 @@ mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
id = get_sym_or_str_arg(mrb);
if (mrb_symbol_p(id)) {
- method_defined_p = mrb_obj_respond_to(mrb_class_ptr(mod), mrb_symbol(id));
+ method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(id));
}
else {
mrb_value sym = mrb_check_intern_str(mrb, id);
@@ -1712,7 +1753,7 @@ mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
method_defined_p = FALSE;
}
else {
- method_defined_p = mrb_obj_respond_to(mrb_class_ptr(mod), mrb_symbol(sym));
+ method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(sym));
}
}
return mrb_bool_value(method_defined_p);
@@ -1726,9 +1767,9 @@ remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
khiter_t k;
if (h) {
- k = kh_get(mt, h, mid);
+ k = kh_get(mt, mrb, h, mid);
if (k != kh_end(h)) {
- kh_del(mt, h, k);
+ kh_del(mt, mrb, h, k);
return;
}
}
@@ -1764,7 +1805,7 @@ static void
check_const_name_sym(mrb_state *mrb, mrb_sym id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, id, &len);
if (len < 1 || !ISUPPER(*s)) {
@@ -1843,6 +1884,18 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
return val;
}
+mrb_value
+mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym sym;
+
+ mrb_get_args(mrb, "n", &sym);
+ mrb_name_error(mrb, sym, "uninitialized constant %S",
+ mrb_sym2str(mrb, sym));
+ /* not reached */
+ return mrb_nil_value();
+}
+
static mrb_value
mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
{
@@ -1869,7 +1922,6 @@ mrb_init_class(mrb_state *mrb)
struct RClass *obj; /* Object */
struct RClass *mod; /* Module */
struct RClass *cls; /* Class */
- //struct RClass *krn; /* Kernel */
/* boot class hierarchy */
bob = boot_defclass(mrb, 0);
@@ -1891,10 +1943,10 @@ mrb_init_class(mrb_state *mrb)
mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls));
/* name each classes */
- mrb_name_class(mrb, bob, mrb_intern2(mrb, "BasicObject", 11)); /* 15.2.1 */
- mrb_name_class(mrb, obj, mrb_intern2(mrb, "Object", 6)); /* 15.2.1 */
- mrb_name_class(mrb, mod, mrb_intern2(mrb, "Module", 6)); /* 15.2.2 */
- mrb_name_class(mrb, cls, mrb_intern2(mrb, "Class", 5)); /* 15.2.3 */
+ name_class(mrb, bob, mrb_intern_lit(mrb, "BasicObject"));
+ name_class(mrb, obj, mrb_intern_lit(mrb, "Object")); /* 15.2.1 */
+ name_class(mrb, mod, mrb_intern_lit(mrb, "Module")); /* 15.2.2 */
+ name_class(mrb, cls, mrb_intern_lit(mrb, "Class")); /* 15.2.3 */
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
@@ -1936,6 +1988,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_NONE()); /* 15.2.2.4.24 */
mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
+ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
diff --git a/src/codegen.c b/src/codegen.c
index 34ccd616f..c869285d9 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -5,16 +5,19 @@
*/
#include <ctype.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "mruby.h"
#include "mruby/compile.h"
-#include "mruby/irep.h"
+#include "mruby/proc.h"
#include "mruby/numeric.h"
#include "mruby/string.h"
+#include "mruby/debug.h"
#include "node.h"
#include "opcode.h"
#include "re.h"
+#include "mrb_throw.h"
typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
@@ -25,7 +28,7 @@ enum looptype {
LOOP_FOR,
LOOP_BEGIN,
LOOP_RESCUE,
-} type;
+};
struct loopinfo {
enum looptype type;
@@ -37,7 +40,7 @@ struct loopinfo {
typedef struct scope {
mrb_state *mrb;
mrb_pool *mpool;
- jmp_buf jmp;
+ struct mrb_jmpbuf jmp;
struct scope *prev;
@@ -51,22 +54,25 @@ typedef struct scope {
struct loopinfo *loop;
int ensure_level;
- char *filename;
- short lineno;
+ char const *filename;
+ uint16_t lineno;
mrb_code *iseq;
- short *lines;
+ uint16_t *lines;
int icapa;
mrb_irep *irep;
size_t pcapa;
- int scapa;
+ size_t scapa;
+ size_t rcapa;
int nlocals;
int nregs;
int ai;
- int idx;
+ int debug_start_pos;
+ uint16_t filename_index;
+ parser_state* parser;
} codegen_scope;
static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
@@ -85,10 +91,10 @@ codegen_error(codegen_scope *s, const char *message)
{
if (!s) return;
while (s->prev) {
+ codegen_scope *tmp = s->prev;
mrb_pool_close(s->mpool);
- s = s->prev;
+ s = tmp;
}
- mrb_pool_close(s->mpool);
#ifdef ENABLE_STDIO
if (s->filename && s->lineno) {
fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
@@ -97,7 +103,7 @@ codegen_error(codegen_scope *s, const char *message)
fprintf(stderr, "codegen error: %s\n", message);
}
#endif
- longjmp(s->jmp, 1);
+ MRB_THROW(&s->jmp);
}
static void*
@@ -109,19 +115,19 @@ codegen_palloc(codegen_scope *s, size_t len)
return p;
}
-void*
+static void*
codegen_malloc(codegen_scope *s, size_t len)
{
- void *p = mrb_malloc(s->mrb, len);
+ void *p = mrb_malloc_simple(s->mrb, len);
if (!p) codegen_error(s, "mrb_malloc");
return p;
}
-void*
+static void*
codegen_realloc(codegen_scope *s, void *p, size_t len)
{
- p = mrb_realloc(s->mrb, p, len);
+ p = mrb_realloc_simple(s->mrb, p, len);
if (!p && len > 0) codegen_error(s, "mrb_realloc");
return p;
@@ -134,27 +140,28 @@ new_label(codegen_scope *s)
return s->pc;
}
-static inline void
+static inline int
genop(codegen_scope *s, mrb_code i)
{
if (s->pc == s->icapa) {
s->icapa *= 2;
s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
- s->lines = (short*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
+ s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
+ s->irep->lines = s->lines;
}
}
s->iseq[s->pc] = i;
if (s->lines) {
s->lines[s->pc] = s->lineno;
}
- s->pc++;
+ return s->pc++;
}
#define NOVAL 0
#define VAL 1
-static void
+static int
genop_peep(codegen_scope *s, mrb_code i, int val)
{
/* peephole optimization */
@@ -167,24 +174,24 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_MOVE:
if (GETARG_A(i) == GETARG_B(i)) {
/* skip useless OP_MOVE */
- return;
+ return 0;
}
if (val) break;
switch (c0) {
case OP_MOVE:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0) && GETARG_A(i) >= s->nlocals) {
/* skip swapping OP_MOVE */
- return;
+ return 0;
}
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0));
- return;
+ return 0;
}
break;
case OP_LOADI:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
- return;
+ return 0;
}
break;
case OP_ARRAY:
@@ -194,7 +201,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_GETUPVAR:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
- return;
+ return 0;
}
break;
case OP_LOADSYM:
@@ -207,13 +214,13 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_STRING:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
- return;
+ return 0;
}
break;
case OP_SCLASS:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
- return;
+ return 0;
}
break;
case OP_LOADNIL:
@@ -223,7 +230,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
case OP_OCLASS:
if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
- return;
+ return 0;
}
break;
default:
@@ -239,7 +246,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (c0 == OP_MOVE) {
if (GETARG_A(i) == GETARG_A(i0)) {
s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
- return;
+ return 0;
}
}
break;
@@ -248,41 +255,32 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (c0 == OP_MOVE) {
if (GETARG_A(i) == GETARG_A(i0)) {
s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
- return;
+ return 0;
}
}
break;
case OP_EPOP:
if (c0 == OP_EPOP) {
s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
- return;
+ return 0;
}
break;
case OP_POPERR:
if (c0 == OP_POPERR) {
s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
- return;
+ return 0;
}
break;
case OP_RETURN:
switch (c0) {
case OP_RETURN:
- return;
+ return 0;
case OP_MOVE:
- s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
- return;
- case OP_LOADI:
- s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, 0, GETARG_sBx(i0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- return;
- case OP_ARRAY:
- case OP_HASH:
- case OP_RANGE:
- case OP_AREF:
- case OP_GETUPVAR:
- s->iseq[s->pc-1] = MKOP_ABC(c0, 0, GETARG_B(i0), GETARG_C(i0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- return;
+ if (GETARG_A(i0) >= s->nlocals) {
+ s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
+ return 0;
+ }
+ break;
case OP_SETIV:
case OP_SETCV:
case OP_SETCONST:
@@ -292,31 +290,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
s->pc--;
genop_peep(s, i0, NOVAL);
i0 = s->iseq[s->pc-1];
- genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
- return;
- case OP_LOADSYM:
- case OP_GETGLOBAL:
- case OP_GETIV:
- case OP_GETCV:
- case OP_GETCONST:
- case OP_GETSPECIAL:
- case OP_LOADL:
- case OP_STRING:
- s->iseq[s->pc-1] = MKOP_ABx(c0, 0, GETARG_Bx(i0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- return;
- case OP_SCLASS:
- s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- return;
- case OP_LOADNIL:
- case OP_LOADSELF:
- case OP_LOADT:
- case OP_LOADF:
- case OP_OCLASS:
- s->iseq[s->pc-1] = MKOP_A(c0, 0);
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- return;
+ return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
#if 0
case OP_SEND:
if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
@@ -340,7 +314,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
else
s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
- return;
+ return 0;
}
case OP_STRCAT:
if (c0 == OP_STRING) {
@@ -349,15 +323,22 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
if (mrb_type(s->irep->pool[i]) == MRB_TT_STRING &&
RSTRING_LEN(s->irep->pool[i]) == 0) {
s->pc--;
- return;
+ return 0;
}
}
break;
+ case OP_JMPIF:
+ case OP_JMPNOT:
+ if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
+ s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
+ return s->pc-1;
+ }
+ break;
default:
break;
}
}
- genop(s, i);
+ return genop(s, i);
}
static void
@@ -427,34 +408,65 @@ static inline int
new_lit(codegen_scope *s, mrb_value val)
{
size_t i;
+ mrb_value *pv;
switch (mrb_type(val)) {
case MRB_TT_STRING:
for (i=0; i<s->irep->plen; i++) {
- mrb_value pv = s->irep->pool[i];
mrb_int len;
+ pv = &s->irep->pool[i];
- if (mrb_type(pv) != MRB_TT_STRING) continue;
- if ((len = RSTRING_LEN(pv)) != RSTRING_LEN(val)) continue;
- if (memcmp(RSTRING_PTR(pv), RSTRING_PTR(val), len) == 0)
+ if (mrb_type(*pv) != MRB_TT_STRING) continue;
+ if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
+ if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
return i;
}
break;
case MRB_TT_FLOAT:
- default:
for (i=0; i<s->irep->plen; i++) {
- if (mrb_obj_equal(s->mrb, s->irep->pool[i], val)) return i;
+ pv = &s->irep->pool[i];
+ if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
+ if (mrb_float(*pv) == mrb_float(val)) return i;
}
break;
+ case MRB_TT_FIXNUM:
+ for (i=0; i<s->irep->plen; i++) {
+ pv = &s->irep->pool[i];
+ if (!mrb_fixnum_p(*pv)) continue;
+ if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i;
+ }
+ break;
+ default:
+ /* should not happen */
+ return 0;
}
if (s->irep->plen == s->pcapa) {
s->pcapa *= 2;
s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa);
}
- s->irep->pool[s->irep->plen] = val;
+
+ pv = &s->irep->pool[s->irep->plen];
i = s->irep->plen++;
+ switch (mrb_type(val)) {
+ case MRB_TT_STRING:
+ *pv = mrb_str_pool(s->mrb, val);
+ break;
+
+ case MRB_TT_FLOAT:
+#ifdef MRB_WORD_BOXING
+ *pv = mrb_float_pool(s->mrb, mrb_float(val));
+ break;
+#endif
+ case MRB_TT_FIXNUM:
+ *pv = val;
+ break;
+
+ default:
+ /* should not happen */
+ break;
+ }
return i;
}
@@ -529,21 +541,20 @@ static void
for_body(codegen_scope *s, node *tree)
{
codegen_scope *prev = s;
- int idx, base = s->idx;
+ int idx;
struct loopinfo *lp;
node *n2;
mrb_code c;
- // generate receiver
+ /* generate receiver */
codegen(s, tree->cdr->car, VAL);
- // generate loop-block
+ /* generate loop-block */
s = scope_new(s->mrb, s, tree->car);
- idx = s->idx;
lp = loop_push(s, LOOP_FOR);
lp->pc1 = new_label(s);
- // generate loop variable
+ /* generate loop variable */
n2 = tree->car;
if (n2->car && !n2->car->cdr && !n2->cdr) {
genop(s, MKOP_Ax(OP_ENTER, 0x40000));
@@ -563,20 +574,18 @@ for_body(codegen_scope *s, node *tree)
loop_pop(s, NOVAL);
scope_finish(s);
s = prev;
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx - base, OP_L_BLOCK));
+ genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
pop();
- idx = new_msym(s, mrb_intern2(s->mrb, "each", 4));
+ idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
}
static int
lambda_body(codegen_scope *s, node *tree, int blk)
{
- int idx, base = s->idx;
mrb_code c;
-
+ codegen_scope *parent = s;
s = scope_new(s->mrb, s, tree->car);
- idx = s->idx;
s->mscope = !blk;
if (blk) {
@@ -655,32 +664,36 @@ lambda_body(codegen_scope *s, node *tree, int blk)
loop_pop(s, NOVAL);
}
scope_finish(s);
-
- return idx - base;
+ return parent->irep->rlen - 1;
}
static int
-scope_body(codegen_scope *s, node *tree)
+scope_body(codegen_scope *s, node *tree, int val)
{
codegen_scope *scope = scope_new(s->mrb, s, tree->car);
- int idx = scope->idx;
codegen(scope, tree->cdr, VAL);
if (!s->iseq) {
genop(scope, MKOP_A(OP_STOP, 0));
}
+ else if (!val) {
+ genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
+ }
else {
if (scope->nregs == 0) {
genop(scope, MKOP_A(OP_LOADNIL, 0));
genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
}
else {
- genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp, OP_R_NORMAL), NOVAL);
+ genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL);
}
}
scope_finish(scope);
-
- return idx - s->idx;
+ if (!s->irep) {
+ /* should not happen */
+ return 0;
+ }
+ return s->irep->rlen - 1;
}
static mrb_bool
@@ -697,32 +710,44 @@ static mrb_sym
attrsym(codegen_scope *s, mrb_sym a)
{
const char *name;
- size_t len;
+ mrb_int len;
char *name2;
name = mrb_sym2name_len(s->mrb, a, &len);
- name2 = (char *)codegen_palloc(s, len+1);
- memcpy(name2, name, len);
+ name2 = (char *)codegen_palloc(s,
+ (size_t)len
+ + 1 /* '=' */
+ + 1 /* '\0' */
+ );
+ mrb_assert(len <= SIZE_MAX);
+ memcpy(name2, name, (size_t)len);
name2[len] = '=';
name2[len+1] = '\0';
- return mrb_intern2(s->mrb, name2, len+1);
+ return mrb_intern(s->mrb, name2, len+1);
}
static int
gen_values(codegen_scope *s, node *t, int val)
{
int n = 0;
+ int is_splat;
while (t) {
- if (n >= 127 || (intptr_t)t->car->car == NODE_SPLAT) { // splat mode
+ is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
+ if (n >= 127 || is_splat) {
if (val) {
pop_n(n);
genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
push();
codegen(s, t->car, VAL);
pop(); pop();
- genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+ if (is_splat) {
+ genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+ }
+ else {
+ genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+ }
t = t->cdr;
while (t) {
push();
@@ -747,7 +772,7 @@ gen_values(codegen_scope *s, node *t, int val)
}
return -1;
}
- // normal (no splat) mode
+ /* normal (no splat) mode */
codegen(s, t->car, val);
n++;
t = t->cdr;
@@ -796,7 +821,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val)
}
pop_n(n+1);
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(s->mrb, sym, &len);
if (!noop && len == 1 && name[0] == '+') {
@@ -959,17 +984,20 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
}
}
}
+ else {
+ pop();
+ }
}
static void
gen_send_intern(codegen_scope *s)
{
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "intern", 6)), 0));
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
push();
}
static void
-gen_literal_array(codegen_scope *s, node *tree, int sym, int val)
+gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
{
if (val) {
int i = 0, j = 0;
@@ -1057,7 +1085,7 @@ readint_float(codegen_scope *s, const char *p, int base)
}
static mrb_int
-readint_mrb_int(codegen_scope *s, const char *p, int base, int neg, int *overflow)
+readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow)
{
const char *e = p + strlen(p);
mrb_int result = 0;
@@ -1104,6 +1132,15 @@ codegen(codegen_scope *s, node *tree, int val)
int nt;
if (!tree) return;
+
+ if (s->irep && s->pc > 0 && s->filename_index != tree->filename_index) {
+ s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
+ mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
+ s->debug_start_pos = s->pc;
+ s->filename_index = tree->filename_index;
+ s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
+ }
+
nt = (intptr_t)tree->car;
s->lineno = tree->lineno;
tree = tree->cdr;
@@ -1124,8 +1161,7 @@ codegen(codegen_scope *s, node *tree, int val)
int onerr, noexc, exend, pos1, pos2, tmp;
struct loopinfo *lp;
- onerr = new_label(s);
- genop(s, MKOP_Bx(OP_ONERR, 0));
+ onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
lp = loop_push(s, LOOP_BEGIN);
lp->pc1 = onerr;
if (tree->car) {
@@ -1133,8 +1169,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) pop();
}
lp->type = LOOP_RESCUE;
- noexc = new_label(s);
- genop(s, MKOP_Bx(OP_JMP, 0));
+ noexc = genop(s, MKOP_Bx(OP_JMP, 0));
dispatch(s, onerr);
tree = tree->cdr;
exend = 0;
@@ -1156,21 +1191,24 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, n4->car, VAL);
}
else {
- genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern2(s->mrb, "StandardError", 13))));
+ genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
push();
}
genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "===", 3)), 1));
- tmp = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+ }
+ else {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+ }
+ tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
pos2 = tmp;
if (n4) {
n4 = n4->cdr;
}
} while (n4);
- pos1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch_linked(s, pos2);
pop();
@@ -1181,8 +1219,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, n3->cdr->cdr->car, val);
if (val) pop();
}
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, exend));
+ tmp = genop(s, MKOP_sBx(OP_JMP, exend));
exend = tmp;
n2 = n2->cdr;
push();
@@ -1215,7 +1252,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_Bx(OP_EPUSH, 0));
s->ensure_level++;
codegen(s, tree->car, val);
- idx = scope_body(s, tree->cdr);
+ idx = scope_body(s, tree->cdr, NOVAL);
s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx);
s->ensure_level--;
genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
@@ -1247,8 +1284,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos1 = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+ pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
codegen(s, tree->cdr->car, val);
if (val && !(tree->cdr->car)) {
@@ -1257,17 +1293,15 @@ codegen(codegen_scope *s, node *tree, int val)
}
if (e) {
if (val) pop();
- pos2 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch(s, pos1);
+ pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+ dispatch(s, pos1);
codegen(s, e, val);
dispatch(s, pos2);
}
else {
if (val) {
pop();
- pos2 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch(s, pos1);
genop(s, MKOP_A(OP_LOADNIL, cursp()));
dispatch(s, pos2);
@@ -1285,9 +1319,8 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
codegen(s, tree->car, VAL);
- pos = new_label(s);
pop();
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+ pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1298,9 +1331,8 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
codegen(s, tree->car, VAL);
- pos = new_label(s);
pop();
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+ pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1310,8 +1342,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1327,8 +1358,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1365,39 +1395,47 @@ codegen(codegen_scope *s, node *tree, int val)
if (head) {
genop(s, MKOP_AB(OP_MOVE, cursp(), head));
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "===", 3)), 1));
+ if ((intptr_t)n->car->car == NODE_SPLAT) {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+ }
+ else {
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+ }
}
else {
pop();
}
- tmp = new_label(s);
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
pos2 = tmp;
n = n->cdr;
}
if (tree->car->car) {
- pos1 = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
dispatch_linked(s, pos2);
}
codegen(s, tree->car->cdr, val);
if (val) pop();
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, pos3));
+ tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
pos3 = tmp;
if (pos1) dispatch(s, pos1);
tree = tree->cdr;
}
if (val) {
+ int pos = cursp();
genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ if (pos3) dispatch_linked(s, pos3);
+ pop();
+ genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
push();
}
- if (pos3) dispatch_linked(s, pos3);
+ else if (pos3) {
+ dispatch_linked(s, pos3);
+ }
}
break;
case NODE_SCOPE:
- scope_body(s, tree);
+ scope_body(s, tree, NOVAL);
break;
case NODE_FCALL:
@@ -1467,16 +1505,32 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_HASH:
{
int len = 0;
+ mrb_bool update = FALSE;
while (tree) {
codegen(s, tree->car->car, val);
codegen(s, tree->car->cdr, val);
len++;
tree = tree->cdr;
+ if (val && len == 126) {
+ pop_n(len*2);
+ genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
+ if (update) {
+ pop();
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+ }
+ push();
+ update = TRUE;
+ len = 0;
+ }
}
if (val) {
pop_n(len*2);
genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
+ if (update) {
+ pop();
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+ }
push();
}
}
@@ -1499,7 +1553,7 @@ codegen(codegen_scope *s, node *tree, int val)
int rhs = cursp();
if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) {
- // fixed rhs
+ /* fixed rhs */
t = t->cdr;
while (t) {
codegen(s, t->car, VAL);
@@ -1548,7 +1602,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
}
else {
- // variable rhs
+ /* variable rhs */
codegen(s, t, VAL);
gen_vmassignment(s, tree->car, rhs, val);
}
@@ -1558,7 +1612,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_OP_ASGN:
{
mrb_sym sym = sym(tree->cdr->car);
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(s->mrb, sym, &len);
int idx;
@@ -1569,8 +1623,7 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
pop();
- pos = new_label(s);
- genop(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0));
+ pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL);
codegen(s, tree->cdr->cdr->car, VAL);
pop();
gen_assignment(s, tree->car, cursp(), val);
@@ -1705,7 +1758,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
pop_n(n+1);
if (sendv) n = CALL_MAXARGS;
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern2(s->mrb, "call", 4)), n));
+ genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
if (val) push();
}
break;
@@ -1872,7 +1925,7 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_value fix = mrb_fixnum_value((intptr_t)tree);
mrb_value str = mrb_str_buf_new(mrb, 4);
- mrb_str_buf_cat(mrb, str, "$", 1);
+ mrb_str_cat_lit(mrb, str, "$");
mrb_str_buf_append(mrb, str, mrb_fixnum_to_str(mrb, fix, 10));
sym = new_sym(s, mrb_intern_str(mrb, str));
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
@@ -1881,7 +1934,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_ARG:
- // should not happen
+ /* should not happen */
break;
case NODE_BLOCK_ARG:
@@ -1894,7 +1947,7 @@ codegen(codegen_scope *s, node *tree, int val)
int base = (intptr_t)tree->cdr->car;
mrb_int i;
mrb_code co;
- int overflow;
+ mrb_bool overflow;
i = readint_mrb_int(s, p, base, FALSE, &overflow);
if (overflow) {
@@ -1950,7 +2003,7 @@ codegen(codegen_scope *s, node *tree, int val)
int base = (intptr_t)tree->cdr->car;
mrb_int i;
mrb_code co;
- int overflow;
+ mrb_bool overflow;
i = readint_mrb_int(s, p, base, TRUE, &overflow);
if (overflow) {
@@ -1975,7 +2028,7 @@ codegen(codegen_scope *s, node *tree, int val)
default:
{
- int sym = new_msym(s, mrb_intern2(s->mrb, "-", 1));
+ int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
push();
@@ -2038,23 +2091,58 @@ codegen(codegen_scope *s, node *tree, int val)
gen_literal_array(s, tree, TRUE, val);
break;
+ case NODE_DXSTR:
+ {
+ node *n;
+ int ai = mrb_gc_arena_save(s->mrb);
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
+
+ if (val == NOVAL) { push(); }
+ genop(s, MKOP_A(OP_OCLASS, cursp()));
+ genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ push();
+ codegen(s, tree->car, VAL);
+ n = tree->cdr;
+ while (n) {
+ if ((intptr_t)n->car->car == NODE_XSTR) {
+ n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
+ mrb_assert(!n->cdr); /* must be the end */
+ }
+ codegen(s, n->car, VAL);
+ pop(); pop();
+ genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ push();
+ n = n->cdr;
+ }
+ pop();
+ pop();
+ sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
+ genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ if (val == NOVAL) { pop(); }
+ else { push(); }
+ mrb_gc_arena_restore(s->mrb, ai);
+ }
+ break;
+
case NODE_XSTR:
- if (val) {
+ {
char *p = (char*)tree->car;
size_t len = (intptr_t)tree->cdr;
int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern2(s->mrb, "Kernel", 6));
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
int off = new_lit(s, mrb_str_new(s->mrb, p, len));
+ if (val == NOVAL) { push(); }
genop(s, MKOP_A(OP_OCLASS, cursp()));
genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
push();
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
pop();
- sym = new_sym(s, mrb_intern2(s->mrb, "`", 1));
+ sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ if (val == NOVAL) { pop(); }
+ else { push(); }
mrb_gc_arena_restore(s->mrb, ai);
- push();
}
break;
@@ -2063,8 +2151,8 @@ codegen(codegen_scope *s, node *tree, int val)
char *p1 = (char*)tree->car;
char *p2 = (char*)tree->cdr;
int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern2(s->mrb, REGEXP_CLASS, REGEXP_CLASS_CSTR_LEN));
- int off = new_lit(s, mrb_str_new(s->mrb, p1, strlen(p1)));
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
+ int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1));
int argc = 1;
genop(s, MKOP_A(OP_OCLASS, cursp()));
@@ -2073,13 +2161,13 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
if (p2) {
push();
- off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
argc++;
pop();
}
pop();
- sym = new_sym(s, mrb_intern2(s->mrb, "compile", 7));
+ sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
mrb_gc_arena_restore(s->mrb, ai);
push();
@@ -2090,7 +2178,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
node *n = tree->car;
int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern2(s->mrb, REGEXP_CLASS, REGEXP_CLASS_CSTR_LEN));
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
int argc = 1;
int off;
char *p;
@@ -2110,7 +2198,7 @@ codegen(codegen_scope *s, node *tree, int val)
n = tree->cdr->cdr;
if (n->car) {
p = (char*)n->car;
- off = new_lit(s, mrb_str_new(s->mrb, p, strlen(p)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
codegen(s, tree->car, VAL);
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
pop();
@@ -2121,13 +2209,13 @@ codegen(codegen_scope *s, node *tree, int val)
int off;
push();
- off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
argc++;
pop();
}
pop();
- sym = new_sym(s, mrb_intern2(s->mrb, "compile", 7));
+ sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
mrb_gc_arena_restore(s->mrb, ai);
push();
@@ -2192,7 +2280,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
int a = new_msym(s, sym(tree->car));
int b = new_msym(s, sym(tree->cdr));
- int c = new_msym(s, mrb_intern2(s->mrb, "alias_method", 12));
+ int c = new_msym(s, mrb_intern_lit(s->mrb,"alias_method"));
genop(s, MKOP_A(OP_TCLASS, cursp()));
push();
@@ -2211,7 +2299,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_UNDEF:
{
- int undef = new_msym(s, mrb_intern2(s->mrb, "undef_method", 12));
+ int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
int num = 0;
node *t = tree;
@@ -2257,7 +2345,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop(); pop();
idx = new_msym(s, sym(tree->car->cdr));
genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
- idx = scope_body(s, tree->cdr->cdr->car);
+ idx = scope_body(s, tree->cdr->cdr->car, val);
genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
if (val) {
push();
@@ -2283,7 +2371,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
idx = new_msym(s, sym(tree->car->cdr));
genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
- idx = scope_body(s, tree->cdr->car);
+ idx = scope_body(s, tree->cdr->car, val);
genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
if (val) {
push();
@@ -2298,7 +2386,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
- idx = scope_body(s, tree->cdr->car);
+ idx = scope_body(s, tree->cdr->car, val);
genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
if (val) {
push();
@@ -2317,7 +2405,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
push();
}
}
@@ -2337,7 +2425,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
push();
}
}
@@ -2352,6 +2440,21 @@ codegen(codegen_scope *s, node *tree, int val)
}
}
+static void
+scope_add_irep(codegen_scope *s, mrb_irep *irep)
+{
+ if (s->irep == NULL) {
+ s->irep = irep;
+ return;
+ }
+ if (s->irep->rlen == s->rcapa) {
+ s->rcapa *= 2;
+ s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa);
+ }
+ s->irep->reps[s->irep->rlen] = irep;
+ s->irep->rlen++;
+}
+
static codegen_scope*
scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
{
@@ -2369,17 +2472,21 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->mscope = 0;
p->irep = mrb_add_irep(mrb);
- p->idx = p->irep->idx;
+ scope_add_irep(prev, p->irep);
+
+ p->rcapa = 8;
+ p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa);
p->icapa = 1024;
p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa);
+ p->irep->iseq = p->iseq;
p->pcapa = 32;
p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa);
p->irep->plen = 0;
p->scapa = 256;
- p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*256);
+ p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
p->irep->slen = 0;
p->lv = lv;
@@ -2389,9 +2496,23 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->filename = prev->filename;
if (p->filename) {
- p->lines = (short*)mrb_malloc(mrb, sizeof(short)*p->icapa);
+ p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
}
p->lineno = prev->lineno;
+
+ /* debug setting */
+ p->debug_start_pos = 0;
+ if (p->filename) {
+ mrb_debug_info_alloc(mrb, p->irep);
+ p->irep->filename = p->filename;
+ p->irep->lines = p->lines;
+ }
+ else {
+ p->irep->debug_info = NULL;
+ }
+ p->parser = prev->parser;
+ p->filename_index = prev->filename_index;
+
return p;
}
@@ -2414,11 +2535,15 @@ scope_finish(codegen_scope *s)
irep->lines = 0;
}
}
- irep->pool = (mrb_value *)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
- irep->syms = (mrb_sym *)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
+ irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
+ irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
+ irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
if (s->filename) {
+ s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
+ mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc);
+
fname_len = strlen(s->filename);
- fname = codegen_malloc(s, fname_len + 1);
+ fname = (char*)codegen_malloc(s, fname_len + 1);
memcpy(fname, s->filename, fname_len);
fname[fname_len] = '\0';
irep->filename = fname;
@@ -2478,8 +2603,7 @@ loop_break(codegen_scope *s, node *tree)
if (tree) {
genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
}
- tmp = new_label(s);
- genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+ tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
loop->pc3 = tmp;
}
else {
@@ -2500,18 +2624,19 @@ loop_pop(codegen_scope *s, int val)
}
static void
-codedump(mrb_state *mrb, int n)
+codedump(mrb_state *mrb, mrb_irep *irep)
{
#ifdef ENABLE_STDIO
- mrb_irep *irep = mrb->irep[n];
- uint32_t i;
+ int i;
int ai;
mrb_code c;
if (!irep) return;
- printf("irep %d nregs=%d nlocals=%d pools=%d syms=%d\n", n,
- irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen);
- for (i=0; i<irep->ilen; i++) {
+ printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", irep,
+ irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
+
+ mrb_assert(irep->ilen <= INT_MAX);
+ for (i = 0; i < (int)(irep->ilen); i++) {
ai = mrb_gc_arena_save(mrb);
printf("%03d ", i);
c = irep->iseq[i];
@@ -2666,7 +2791,7 @@ codedump(mrb_state *mrb, int n)
break;
case OP_LAMBDA:
- printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c), GETARG_c(c));
+ printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c));
break;
case OP_RANGE:
printf("OP_RANGE\tR%d\tR%d\t%d\n", GETARG_A(c), GETARG_B(c), GETARG_C(c));
@@ -2753,9 +2878,8 @@ codedump(mrb_state *mrb, int n)
break;
case OP_STRING:
{
- mrb_value s = irep->pool[GETARG_Bx(c)];
-
- s = mrb_str_dump(mrb, s);
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
printf("OP_STRING\tR%d\t%s\n", GETARG_A(c), RSTRING_PTR(s));
}
break;
@@ -2778,7 +2902,7 @@ codedump(mrb_state *mrb, int n)
mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
break;
case OP_EXEC:
- printf("OP_EXEC\tR%d\tI(%d)\n", GETARG_A(c), n+GETARG_Bx(c));
+ printf("OP_EXEC\tR%d\tI(%+d)\n", GETARG_A(c), GETARG_Bx(c)+1);
break;
case OP_SCLASS:
printf("OP_SCLASS\tR%d\tR%d\n", GETARG_A(c), GETARG_B(c));
@@ -2787,10 +2911,14 @@ codedump(mrb_state *mrb, int n)
printf("OP_TCLASS\tR%d\n", GETARG_A(c));
break;
case OP_ERR:
- printf("OP_ERR\tL(%d)\n", GETARG_Bx(c));
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+ printf("OP_ERR\t%s\n", RSTRING_PTR(s));
+ }
break;
case OP_EPUSH:
- printf("OP_EPUSH\t:I(%d)\n", n+GETARG_Bx(c));
+ printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
break;
case OP_ONERR:
printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
@@ -2819,47 +2947,52 @@ codedump(mrb_state *mrb, int n)
#endif
}
-void
-codedump_all(mrb_state *mrb, int start)
+static void
+codedump_recur(mrb_state *mrb, mrb_irep *irep)
{
size_t i;
- for (i=start; i<mrb->irep_len; i++) {
- codedump(mrb, i);
+ codedump(mrb, irep);
+ for (i=0; i<irep->rlen; i++) {
+ codedump_recur(mrb, irep->reps[i]);
}
}
-static int
-codegen_start(mrb_state *mrb, parser_state *p)
+void
+mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
+{
+ codedump_recur(mrb, proc->body.irep);
+}
+
+struct RProc*
+mrb_generate_code(mrb_state *mrb, parser_state *p)
{
codegen_scope *scope = scope_new(mrb, 0, 0);
+ struct RProc *proc;
if (!scope) {
- return -1;
+ return NULL;
}
scope->mrb = mrb;
- if (p->filename) {
- scope->filename = p->filename;
- }
- if (setjmp(scope->jmp) == 0) {
- // prepare irep
+ scope->parser = p;
+ scope->filename = p->filename;
+ scope->filename_index = p->current_filename_index;
+
+ MRB_TRY(&scope->jmp) {
+ /* prepare irep */
codegen(scope, p->tree, NOVAL);
+ proc = mrb_proc_new(mrb, scope->irep);
+ mrb_irep_decref(mrb, scope->irep);
mrb_pool_close(scope->mpool);
- return 0;
+ return proc;
}
- else {
- return -1;
+ MRB_CATCH(&scope->jmp) {
+ if (scope->filename == scope->irep->filename) {
+ scope->irep->filename = NULL;
+ }
+ mrb_irep_decref(mrb, scope->irep);
+ mrb_pool_close(scope->mpool);
+ return NULL;
}
-}
-
-int
-mrb_generate_code(mrb_state *mrb, parser_state *p)
-{
- int start = mrb->irep_len;
- int n;
-
- n = codegen_start(mrb, p);
- if (n < 0) return n;
-
- return start;
+ MRB_END_EXC(&scope->jmp);
}
diff --git a/src/crc.c b/src/crc.c
index 3bda7bc26..290b2ca0e 100644
--- a/src/crc.c
+++ b/src/crc.c
@@ -8,12 +8,13 @@
#include <stdint.h>
#include <stddef.h>
-// Calculate CRC (CRC-16-CCITT)
-//
-// 0000_0000_0000_0000_0000_0000_0000_0000
-// ^|------- CRC -------|- work --|
-// carry
-#define CRC_16_CCITT 0x11021ul //x^16+x^12+x^5+1
+/* Calculate CRC (CRC-16-CCITT)
+**
+** 0000_0000_0000_0000_0000_0000_0000_0000
+** ^|------- CRC -------|- work --|
+** carry
+*/
+#define CRC_16_CCITT 0x11021ul /* x^16+x^12+x^5+1 */
#define CRC_XOR_PATTERN (CRC_16_CCITT << 8)
#define CRC_CARRY_BIT (0x01000000)
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 000000000..0af0f48f7
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,215 @@
+#include <string.h>
+#include "mruby.h"
+#include "mruby/irep.h"
+#include "mruby/debug.h"
+
+static mrb_irep_debug_info_file *
+get_file(mrb_irep_debug_info *info, uint32_t pc)
+{
+ mrb_irep_debug_info_file **ret;
+ int32_t count;
+
+ if (pc >= info->pc_count) { return NULL; }
+ /* get upper bound */
+ ret = info->files;
+ count = info->flen;
+ while (count > 0) {
+ int32_t step = count / 2;
+ mrb_irep_debug_info_file **it = ret + step;
+ if (!(pc < (*it)->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ } else { count = step; }
+ }
+
+ --ret;
+
+ /* check returning file exists inside debug info */
+ mrb_assert(info->files <= ret && ret < (info->files + info->flen));
+ /* check pc is within the range of returning file */
+ mrb_assert((*ret)->start_pos <= pc &&
+ pc < (((ret + 1 - info->files) < info->flen)
+ ? (*(ret+1))->start_pos : info->pc_count));
+
+ return *ret;
+}
+
+static mrb_debug_line_type
+select_line_type(const uint16_t *lines, size_t lines_len)
+{
+ size_t line_count = 0;
+ int prev_line = -1;
+ size_t i;
+ for (i = 0; i < lines_len; ++i) {
+ if (lines[i] != prev_line) {
+ ++line_count;
+ }
+ }
+ return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count)
+ ? mrb_debug_line_ary : mrb_debug_line_flat_map;
+}
+
+char const*
+mrb_debug_get_filename(mrb_irep *irep, uint32_t pc)
+{
+ if (irep && pc < irep->ilen) {
+ mrb_irep_debug_info_file* f = NULL;
+ if (!irep->debug_info) { return irep->filename; }
+ else if ((f = get_file(irep->debug_info, pc))) {
+ return f->filename;
+ }
+ }
+ return NULL;
+}
+
+int32_t
+mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
+{
+ if (irep && pc < irep->ilen) {
+ mrb_irep_debug_info_file* f = NULL;
+ if (!irep->debug_info) {
+ return irep->lines? irep->lines[pc] : -1;
+ }
+ else if ((f = get_file(irep->debug_info, pc))) {
+ switch (f->line_type) {
+ case mrb_debug_line_ary:
+ mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count));
+ return f->lines.ary[pc - f->start_pos];
+
+ case mrb_debug_line_flat_map: {
+ /* get upper bound */
+ mrb_irep_debug_info_line *ret = f->lines.flat_map;
+ uint32_t count = f->line_entry_count;
+ while (count > 0) {
+ int32_t step = count / 2;
+ mrb_irep_debug_info_line *it = ret + step;
+ if (!(pc < it->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ } else { count = step; }
+ }
+
+ --ret;
+
+ /* check line entry pointer range */
+ mrb_assert(f->lines.flat_map <= ret && ret < (f->lines.flat_map + f->line_entry_count));
+ /* check pc range */
+ mrb_assert(ret->start_pos <= pc &&
+ pc < (((ret + 1 - f->lines.flat_map) < f->line_entry_count)
+ ? (ret+1)->start_pos : irep->debug_info->pc_count));
+
+ return ret->line;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+mrb_irep_debug_info *
+mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep)
+{
+ static const mrb_irep_debug_info initial = { 0, 0, NULL };
+ mrb_irep_debug_info *ret;
+
+ mrb_assert(!irep->debug_info);
+ ret = (mrb_irep_debug_info *)mrb_malloc(mrb, sizeof(*ret));
+ *ret = initial;
+ irep->debug_info = ret;
+ return ret;
+}
+
+mrb_irep_debug_info_file *
+mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
+ uint32_t start_pos, uint32_t end_pos)
+{
+ mrb_irep_debug_info *info;
+ mrb_irep_debug_info_file *ret;
+ uint32_t file_pc_count;
+ size_t fn_len;
+ mrb_int len;
+ uint32_t i;
+
+ if (!irep->debug_info) { return NULL; }
+
+ mrb_assert(irep->filename);
+ mrb_assert(irep->lines);
+
+ info = irep->debug_info;
+
+ if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) {
+ return NULL;
+ }
+
+ ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret));
+ info->files =
+ (mrb_irep_debug_info_file**)(
+ info->files
+ ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1))
+ : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*)));
+ info->files[info->flen++] = ret;
+
+ file_pc_count = end_pos - start_pos;
+
+ ret->start_pos = start_pos;
+ info->pc_count = end_pos;
+
+ fn_len = strlen(irep->filename);
+ ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len);
+ len = 0;
+ ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len);
+
+ ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos);
+ ret->lines.ptr = NULL;
+
+ switch (ret->line_type) {
+ case mrb_debug_line_ary:
+ ret->line_entry_count = file_pc_count;
+ ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
+ for (i = 0; i < file_pc_count; ++i) {
+ ret->lines.ary[i] = irep->lines[start_pos + i];
+ }
+ break;
+
+ case mrb_debug_line_flat_map: {
+ uint16_t prev_line = 0;
+ mrb_irep_debug_info_line m;
+ ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
+ ret->line_entry_count = 0;
+ for (i = 0; i < file_pc_count; ++i) {
+ if (irep->lines[start_pos + i] == prev_line) { continue; }
+
+ ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc(
+ mrb, ret->lines.flat_map,
+ sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1));
+ m.start_pos = start_pos + i;
+ m.line = irep->lines[start_pos + i];
+ ret->lines.flat_map[ret->line_entry_count] = m;
+
+ /* update */
+ ++ret->line_entry_count;
+ prev_line = irep->lines[start_pos + i];
+ }
+ } break;
+
+ default: mrb_assert(0); break;
+ }
+
+ return ret;
+}
+
+void
+mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
+{
+ uint32_t i;
+
+ if (!d) { return; }
+
+ for (i = 0; i < d->flen; ++i) {
+ mrb_assert(d->files[i]);
+ mrb_free(mrb, d->files[i]->lines.ptr);
+ mrb_free(mrb, d->files[i]);
+ }
+ mrb_free(mrb, d->files);
+ mrb_free(mrb, d);
+}
diff --git a/src/dump.c b/src/dump.c
index 72ca9e0c3..bdfa0787f 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -4,61 +4,69 @@
** See Copyright Notice in mruby.h
*/
+#include <ctype.h>
#include <string.h>
+#include <limits.h>
#include "mruby/dump.h"
-#include <ctype.h>
-
#include "mruby/string.h"
#include "mruby/irep.h"
#include "mruby/numeric.h"
+#include "mruby/debug.h"
-static size_t get_irep_record_size(mrb_state *mrb, mrb_irep *irep);
+static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
-static uint32_t
+#if UINT32_MAX > SIZE_MAX
+# error This code cannot be built on your environment.
+#endif
+
+static size_t
get_irep_header_size(mrb_state *mrb)
{
- uint32_t size = 0;
+ size_t size = 0;
size += sizeof(uint32_t) * 1;
- size += sizeof(uint16_t) * 2;
+ size += sizeof(uint16_t) * 3;
return size;
}
-static size_t
+static ptrdiff_t
write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
- cur += uint32_to_bin(get_irep_record_size(mrb, irep), cur); /* record size */
+ cur += uint32_to_bin(get_irep_record_size_1(mrb, irep), cur); /* record size */
cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */
cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
+ cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */
- return (cur - buf);
+ return cur - buf;
}
-static uint32_t
+static size_t
get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
{
- uint32_t size = 0;
+ size_t size = 0;
+
size += sizeof(uint32_t); /* ilen */
size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
+
return size;
}
-static int
+static ptrdiff_t
write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
- size_t iseq_no;
+ uint32_t iseq_no;
cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
}
- return (cur - buf);
+ return cur - buf;
}
@@ -67,7 +75,6 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
size_t pool_no;
- int len;
mrb_value str;
char buf[32];
@@ -80,35 +87,48 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
switch (mrb_type(irep->pool[pool_no])) {
case MRB_TT_FIXNUM:
str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
- size += RSTRING_LEN(str);
+ {
+ mrb_int len = RSTRING_LEN(str);
+ mrb_assert(len >= 0);
+ mrb_assert(len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
case MRB_TT_FLOAT:
- len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
- size += len;
+ {
+ int len;
+ len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
+ mrb_assert(len >= 0);
+ mrb_assert(len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
case MRB_TT_STRING:
- str = mrb_str_to_str(mrb, irep->pool[pool_no]);
- size += RSTRING_LEN(str);
+ {
+ mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
+ mrb_assert(len >= 0);
+ mrb_assert(len <= SIZE_MAX);
+ size += (size_t)len;
+ }
break;
default:
break;
}
-
mrb_gc_arena_restore(mrb, ai);
}
return size;
}
-static int
+static ptrdiff_t
write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
size_t pool_no;
uint8_t *cur = buf;
- size_t len;
+ uint16_t len;
mrb_value str;
const char *char_ptr;
char char_buf[30];
@@ -118,24 +138,42 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
for (pool_no = 0; pool_no < irep->plen; pool_no++) {
int ai = mrb_gc_arena_save(mrb);
- cur += uint8_to_bin(mrb_type(irep->pool[pool_no]), cur); /* data type */
-
switch (mrb_type(irep->pool[pool_no])) {
case MRB_TT_FIXNUM:
+ cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
char_ptr = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
+ {
+ mrb_int tlen;
+ tlen = RSTRING_LEN(str);
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
break;
case MRB_TT_FLOAT:
- len = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
+ cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
+ {
+ int tlen;
+ tlen = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
char_ptr = &char_buf[0];
break;
case MRB_TT_STRING:
- str = irep->pool[pool_no];
- char_ptr = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
+ cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
+ char_ptr = RSTRING_PTR(irep->pool[pool_no]);
+ {
+ mrb_int tlen;
+ tlen = RSTRING_LEN(irep->pool[pool_no]);
+ mrb_assert(tlen >= 0);
+ mrb_assert(tlen <= INT16_MAX);
+ len = (uint16_t)tlen;
+ }
break;
default:
@@ -143,13 +181,13 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
}
cur += uint16_to_bin(len, cur); /* data length */
- memcpy(cur, char_ptr, len);
+ memcpy(cur, char_ptr, (size_t)len);
cur += len;
mrb_gc_arena_restore(mrb, ai);
}
- return (int)(cur - buf);
+ return cur - buf;
}
@@ -157,8 +195,8 @@ static size_t
get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
- size_t sym_no;
- size_t len;
+ uint32_t sym_no;
+ mrb_int len;
size += sizeof(uint32_t); /* slen */
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
@@ -172,10 +210,10 @@ get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
return size;
}
-static int
+static ptrdiff_t
write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
- size_t sym_no;
+ uint32_t sym_no;
uint8_t *cur = buf;
const char *name;
@@ -183,13 +221,11 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
for (sym_no = 0; sym_no < irep->slen; sym_no++) {
if (irep->syms[sym_no] != 0) {
- size_t len;
+ mrb_int len;
name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
- if (len > UINT16_MAX) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
+ mrb_assert(len <= UINT16_MAX);
cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
memcpy(cur, name, len); /* symbol name */
cur += (uint16_t)len;
@@ -200,50 +236,71 @@ write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
}
}
- return (int)(cur - buf);
+ return cur - buf;
}
-
-
static size_t
-get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
+get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
{
- uint32_t size = 0;
+ size_t size = 0;
- //size += sizeof(uint16_t); /* rlen */
size += get_irep_header_size(mrb);
size += get_iseq_block_size(mrb, irep);
size += get_pool_block_size(mrb, irep);
size += get_syms_block_size(mrb, irep);
+ return size;
+}
+static size_t
+get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t size = 0;
+ size_t irep_no;
+
+ size = get_irep_record_size_1(mrb, irep);
+ for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
+ size += get_irep_record_size(mrb, irep->reps[irep_no]);
+ }
return size;
}
static int
-write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, uint32_t *irep_record_size)
+write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_record_size)
{
+ uint32_t i;
+
if (irep == NULL) {
return MRB_DUMP_INVALID_IREP;
}
- *irep_record_size = get_irep_record_size(mrb, irep);
+ *irep_record_size = get_irep_record_size_1(mrb, irep);
if (*irep_record_size == 0) {
return MRB_DUMP_GENERAL_FAILURE;
}
memset(bin, 0, *irep_record_size);
- //bin += uint16_to_bin(*irep_record_size, bin);
bin += write_irep_header(mrb, irep, bin);
bin += write_iseq_block(mrb, irep, bin);
bin += write_pool_block(mrb, irep, bin);
bin += write_syms_block(mrb, irep, bin);
+ for (i = 0; i < irep->rlen; i++) {
+ int result;
+ size_t rsize;
+
+ result = write_irep_record(mrb, irep->reps[i], bin, &rsize);
+ if (result != MRB_DUMP_OK) {
+ return result;
+ }
+ *irep_record_size += rsize;
+ bin += rsize;
+ }
return MRB_DUMP_OK;
}
-static size_t
-mrb_write_eof(mrb_state *mrb, uint8_t *bin)
+static uint32_t
+write_footer(mrb_state *mrb, uint8_t *bin)
{
struct rite_binary_footer footer;
@@ -256,92 +313,90 @@ mrb_write_eof(mrb_state *mrb, uint8_t *bin)
static int
-mrb_write_section_irep_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
-{
+write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
+{
struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
- uint32_to_bin(section_size, header->section_size);
+ mrb_assert(section_size <= UINT32_MAX);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
- uint16_to_bin(nirep, header->nirep);
- uint16_to_bin(sirep, header->sirep);
return MRB_DUMP_OK;
}
static int
-mrb_write_section_irep(mrb_state *mrb, size_t start_index, uint8_t *bin)
+write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
{
int result;
- size_t irep_no;
- uint32_t section_size = 0, rlen = 0; /* size of irep record */
+ size_t section_size = 0; /* size of irep record */
+ size_t rsize = 0;
uint8_t *cur = bin;
- if (mrb == NULL || start_index >= mrb->irep_len || bin == NULL) {
+ if (mrb == NULL || bin == NULL) {
return MRB_DUMP_INVALID_ARGUMENT;
}
cur += sizeof(struct rite_section_irep_header);
section_size += sizeof(struct rite_section_irep_header);
- for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
- result = write_irep_record(mrb, mrb->irep[irep_no], cur, &rlen);
- if (result != MRB_DUMP_OK) {
- return result;
- }
- cur += rlen;
- section_size += rlen;
+ result = write_irep_record(mrb, irep, cur, &rsize);
+ if (result != MRB_DUMP_OK) {
+ return result;
}
-
- mrb_write_section_irep_header(mrb, section_size, mrb->irep_len - start_index, start_index, bin);
+ cur += rsize;
+ section_size += rsize;
+ write_section_irep_header(mrb, section_size, bin);
return MRB_DUMP_OK;
}
static int
-mrb_write_section_lineno_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
-{
+write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
+{
struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
- // TODO
memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify));
- uint32_to_bin(section_size, header->section_size);
- uint16_to_bin(nirep, header->nirep);
- uint16_to_bin(sirep, header->sirep);
+ uint32_to_bin((uint32_t)section_size, header->section_size);
return MRB_DUMP_OK;
}
static size_t
-get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
+get_lineno_record_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
- size += sizeof(uint32_t); // record size
- size += sizeof(uint16_t); // filename size
+ size += sizeof(uint32_t); /* record size */
+ size += sizeof(uint16_t); /* filename size */
if (irep->filename) {
- size += strlen(irep->filename); // filename
+ size += strlen(irep->filename); /* filename */
}
- size += sizeof(uint32_t); // niseq
+ size += sizeof(uint32_t); /* niseq */
if (irep->lines) {
- size += sizeof(uint16_t) * irep->ilen; // lineno
+ size += sizeof(uint16_t) * irep->ilen; /* lineno */
}
return size;
}
-static int
-write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
+static size_t
+write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
{
uint8_t *cur = bin;
- size_t filename_len = 0, iseq_no;
+ size_t iseq_no;
+ size_t filename_len;
+ ptrdiff_t diff;
cur += sizeof(uint32_t); /* record size */
if (irep->filename) {
filename_len = strlen(irep->filename);
+ } else {
+ filename_len = 0;
}
- cur += uint16_to_bin(filename_len, cur); /* filename size */
+ mrb_assert(filename_len <= UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */
if (filename_len) {
memcpy(cur, irep->filename, filename_len);
@@ -349,7 +404,8 @@ write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
}
if (irep->lines) {
- cur += uint32_to_bin(irep->ilen, cur); /* niseq */
+ mrb_assert(irep->ilen <= UINT32_MAX);
+ cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */
}
@@ -358,49 +414,302 @@ write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
cur += uint32_to_bin(0, cur); /* niseq */
}
- uint32_to_bin(cur - bin, bin); /* record size */
+ diff = cur - bin;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= UINT32_MAX);
- return (cur - bin);
+ uint32_to_bin((uint32_t)diff, bin); /* record size */
+
+ mrb_assert(diff <= SIZE_MAX);
+ return (size_t)diff;
+}
+
+static size_t
+write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
+{
+ size_t i;
+ size_t rlen, size = 0;
+
+ rlen = write_lineno_record_1(mrb, irep, bin);
+ bin += rlen;
+ size += rlen;
+ for (i=0; i<irep->rlen; i++) {
+ rlen = write_lineno_record(mrb, irep, bin);
+ bin += rlen;
+ size += rlen;
+ }
+ return size;
}
static int
-mrb_write_section_lineno(mrb_state *mrb, size_t start_index, uint8_t *bin)
+write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
{
- size_t irep_no;
- uint32_t section_size = 0, rlen = 0; /* size of irep record */
+ size_t section_size = 0;
+ size_t rlen = 0; /* size of irep record */
uint8_t *cur = bin;
- if (mrb == NULL || start_index >= mrb->irep_len || bin == NULL) {
+ if (mrb == NULL || bin == NULL) {
return MRB_DUMP_INVALID_ARGUMENT;
}
cur += sizeof(struct rite_section_lineno_header);
section_size += sizeof(struct rite_section_lineno_header);
- for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
- rlen = write_lineno_record(mrb, mrb->irep[irep_no], cur);
- cur += rlen;
- section_size += rlen;
+ rlen = write_lineno_record(mrb, irep, cur);
+ section_size += rlen;
+
+ write_section_lineno_header(mrb, section_size, bin);
+
+ return MRB_DUMP_OK;
+}
+
+static size_t
+get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t ret = 0;
+ uint16_t f_idx;
+ size_t i;
+
+ ret += sizeof(uint32_t); /* record size */
+ ret += sizeof(uint16_t); /* file count */
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
+
+ ret += sizeof(uint32_t); /* position */
+ ret += sizeof(uint16_t); /* filename index */
+
+ /* lines */
+ ret += sizeof(uint32_t); /* entry count */
+ ret += sizeof(uint8_t); /* line type */
+ switch (file->line_type) {
+ case mrb_debug_line_ary:
+ ret += sizeof(uint16_t) * (size_t)(file->line_entry_count);
+ break;
+
+ case mrb_debug_line_flat_map:
+ ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
+ break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+ for (i=0; i<irep->rlen; i++) {
+ ret += get_debug_record_size(mrb, irep->reps[i]);
+ }
+
+ return ret;
+}
+
+static int
+find_filename_index(const mrb_sym *ary, uint16_t ary_len, mrb_sym s)
+{
+ int i;
+
+ for (i = 0; i < ary_len; ++i) {
+ if (ary[i] == s) { return i; }
+ }
+ return -1;
+}
+
+static size_t
+get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
+{
+ mrb_sym *filenames = *fp;
+ uint16_t tsize = 0;
+ uint32_t file_i;
+ size_t size = 0;
+ mrb_irep_debug_info *di = irep->debug_info;
+
+ if (lp == NULL) {
+ lp = &tsize;
+ }
+ for (file_i = 0; file_i < di->flen; ++file_i) {
+ mrb_irep_debug_info_file *file;
+ mrb_int filename_len;
+ size_t i;
+
+ file = di->files[file_i];
+ if (find_filename_index(filenames, *lp, file->filename_sym) == -1) {
+ /* register filename */
+ *lp += 1;
+ *fp = filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
+ filenames[*lp - 1] = file->filename_sym;
+
+ /* filename */
+ mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
+ size += sizeof(uint16_t) + (size_t)filename_len;
+ }
+ for (i=0; i<irep->rlen; i++) {
+ size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
+ filenames = *fp;
+ }
+ }
+ return size;
+}
+
+static size_t
+write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+{
+ uint8_t *cur;
+ uint16_t f_idx;
+ ptrdiff_t ret;
+
+ cur = bin + sizeof(uint32_t); /* skip record size */
+ cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ int filename_idx;
+ const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx];
+
+ /* position */
+ cur += uint32_to_bin(file->start_pos, cur);
+
+ /* filename index */
+ filename_idx = find_filename_index(filenames, filenames_len,
+ file->filename_sym);
+ mrb_assert(filename_idx >= 0);
+ mrb_assert(filename_idx <= UINT16_MAX);
+ cur += uint16_to_bin((uint16_t)filename_idx, cur);
+
+ /* lines */
+ cur += uint32_to_bin(file->line_entry_count, cur);
+ cur += uint8_to_bin(file->line_type, cur);
+ switch (file->line_type) {
+ case mrb_debug_line_ary: {
+ uint32_t l;
+ for (l = 0; l < file->line_entry_count; ++l) {
+ cur += uint16_to_bin(file->lines.ary[l], cur);
+ }
+ } break;
+
+ case mrb_debug_line_flat_map: {
+ uint32_t line;
+ for (line = 0; line < file->line_entry_count; ++line) {
+ cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur);
+ cur += uint16_to_bin(file->lines.flat_map[line].line, cur);
+ }
+ } break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+
+ ret = cur - bin;
+ mrb_assert(ret >= 0);
+ mrb_assert(ret <= UINT32_MAX);
+ uint32_to_bin(ret, bin);
+
+ mrb_assert(ret <= SIZE_MAX);
+ return (size_t)ret;
+}
+
+static size_t
+write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
+{
+ size_t size, len;
+ size_t irep_no;
+
+ size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len);
+ bin += len;
+ for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
+ len = write_debug_record(mrb, irep->reps[irep_no], bin, filenames, filenames_len);
+ bin += len;
+ size += len;
+ }
+
+ mrb_assert(size == get_debug_record_size(mrb, irep));
+ return size;
+}
+
+static size_t
+write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp, uint16_t *lp)
+{
+ uint8_t *cur = *cp;
+ mrb_sym *filenames = *fp;
+ uint32_t file_i;
+ uint16_t fn_len;
+ size_t size = 0;
+ mrb_irep_debug_info *debug_info = irep->debug_info;
+
+ for (file_i = 0; file_i < debug_info->flen; ++file_i) {
+ mrb_irep_debug_info_file *file = debug_info->files[file_i];
+ if (find_filename_index(filenames, *lp, file->filename_sym) != -1) continue;
+
+ /* register filename */
+ *lp += 1;
+ *fp = filenames = (mrb_sym*)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
+ filenames[*lp - 1] = file->filename_sym;
+
+ /* filename */
+ fn_len = (uint16_t)strlen(file->filename);
+ cur += uint16_to_bin(fn_len, cur);
+ memcpy(cur, file->filename, fn_len);
+ cur += fn_len;
+
+ size += sizeof(uint16_t) + fn_len;
+ }
+ for (file_i=0; file_i<irep->rlen; file_i++) {
+ size += write_filename_table(mrb, irep->reps[file_i], &cur, fp, lp);
+ }
+ *cp = cur;
+ return size;
+}
+
+static int
+write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur)
+{
+ size_t section_size = 0;
+ const uint8_t *bin = cur;
+ struct rite_section_debug_header *header;
+ mrb_sym *filenames;
+ uint16_t filenames_len = 0;
+ uint8_t *filenames_len_out;
+ size_t dlen;
+
+ if (mrb == NULL || cur == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
}
- mrb_write_section_lineno_header(mrb, section_size, mrb->irep_len - start_index, start_index, bin);
+ header = (struct rite_section_debug_header *)bin;
+ cur += sizeof(struct rite_section_debug_header);
+ section_size += sizeof(struct rite_section_debug_header);
+
+ /* filename table */
+ filenames = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * 1);
+ filenames_len_out = cur;
+ cur += sizeof(uint16_t);
+ section_size += sizeof(uint16_t);
+ section_size += write_filename_table(mrb, irep, &cur, &filenames, &filenames_len);
+ uint16_to_bin(filenames_len, filenames_len_out);
+
+ /* debug records */
+ dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
+ section_size += dlen;
+
+ memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
+ mrb_assert(section_size <= INT32_MAX);
+ uint32_to_bin(section_size, header->section_size);
+
+ mrb_free(mrb, filenames);
return MRB_DUMP_OK;
}
static int
-write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t* bin)
-{
- struct rite_binary_header *header = (struct rite_binary_header*)bin;
+write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin)
+{
+ struct rite_binary_header *header = (struct rite_binary_header *)bin;
uint16_t crc;
- size_t offset;
+ uint32_t offset;
memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify));
memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
- uint32_to_bin(binary_size, header->binary_size);
-
+ mrb_assert(binary_size <= UINT32_MAX);
+ uint32_to_bin((uint32_t)binary_size, header->binary_size);
+
offset = (&(header->binary_crc[0]) - bin) + sizeof(uint16_t);
crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
uint16_to_bin(crc, header->binary_crc);
@@ -408,63 +717,88 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t* bin)
return MRB_DUMP_OK;
}
+static mrb_bool
+is_debug_info_defined(mrb_irep *irep)
+{
+ size_t i;
+
+ if (!irep->debug_info) return 0;
+ for (i=0; i<irep->rlen; i++) {
+ if (!is_debug_info_defined(irep->reps[i])) return 0;
+ }
+ return 1;
+}
+
static int
-mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin, size_t *bin_size)
+dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size)
{
int result = MRB_DUMP_GENERAL_FAILURE;
- size_t section_size = 0;
size_t section_irep_size;
size_t section_lineno_size = 0;
- size_t irep_no;
uint8_t *cur = NULL;
+ mrb_bool const debug_info_defined = is_debug_info_defined(irep);
- if (mrb == NULL || start_index >= mrb->irep_len) {
+ if (mrb == NULL) {
*bin = NULL;
return MRB_DUMP_GENERAL_FAILURE;
}
section_irep_size = sizeof(struct rite_section_irep_header);
- for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
- section_irep_size += get_irep_record_size(mrb, mrb->irep[irep_no]);
- }
- section_size += section_irep_size;
+ section_irep_size += get_irep_record_size(mrb, irep);
/* DEBUG section size */
if (debug_info) {
- section_lineno_size += sizeof(struct rite_section_lineno_header);
- for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
- section_lineno_size += get_debug_record_size(mrb, mrb->irep[irep_no]);
+ if (debug_info_defined) {
+ mrb_sym *filenames;
+
+ section_lineno_size += sizeof(struct rite_section_debug_header);
+ /* filename table */
+ filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1);
+
+ /* filename table size */
+ section_lineno_size += sizeof(uint16_t);
+ section_lineno_size += get_filename_table_size(mrb, irep, &filenames, NULL);
+ mrb_free(mrb, filenames);
+
+ section_lineno_size += get_debug_record_size(mrb, irep);
+ }
+ else {
+ section_lineno_size += sizeof(struct rite_section_lineno_header);
+ section_lineno_size += get_lineno_record_size(mrb, irep);
}
- section_size += section_lineno_size;
}
- *bin_size += sizeof(struct rite_binary_header) + section_size + sizeof(struct rite_binary_footer);
- cur = *bin = (uint8_t *)mrb_malloc(mrb, *bin_size);
+ *bin_size = sizeof(struct rite_binary_header) +
+ section_irep_size + section_lineno_size +
+ sizeof(struct rite_binary_footer);
+ cur = *bin = (uint8_t*)mrb_malloc(mrb, *bin_size);
if (cur == NULL) {
goto error_exit;
}
-
cur += sizeof(struct rite_binary_header);
- result = mrb_write_section_irep(mrb, start_index, cur);
+ result = write_section_irep(mrb, irep, cur);
if (result != MRB_DUMP_OK) {
goto error_exit;
}
-
cur += section_irep_size;
-
+
/* write DEBUG section */
if (debug_info) {
- result = mrb_write_section_lineno(mrb, start_index, cur);
+ if (debug_info_defined) {
+ result = write_section_debug(mrb, irep, cur);
+ }
+ else {
+ result = write_section_lineno(mrb, irep, cur);
+ }
if (result != MRB_DUMP_OK) {
goto error_exit;
}
cur += section_lineno_size;
}
- mrb_write_eof(mrb, cur);
-
- result = write_rite_binary_header(mrb, *bin_size, *bin);
+ write_footer(mrb, cur);
+ write_rite_binary_header(mrb, *bin_size, *bin);
error_exit:
if (result != MRB_DUMP_OK) {
@@ -478,7 +812,7 @@ error_exit:
#ifdef ENABLE_STDIO
int
-mrb_dump_irep_binary(mrb_state *mrb, size_t start_index, int debug_info, FILE* fp)
+mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
{
uint8_t *bin = NULL;
size_t bin_size = 0;
@@ -488,7 +822,7 @@ mrb_dump_irep_binary(mrb_state *mrb, size_t start_index, int debug_info, FILE* f
return MRB_DUMP_INVALID_ARGUMENT;
}
- result = mrb_dump_irep(mrb, start_index, debug_info, &bin, &bin_size);
+ result = dump_irep(mrb, irep, debug_info, &bin, &bin_size);
if (result == MRB_DUMP_OK) {
fwrite(bin, bin_size, 1, fp);
}
@@ -514,7 +848,7 @@ is_valid_c_symbol_name(const char *name)
}
int
-mrb_dump_irep_cfunc(mrb_state *mrb, size_t start_index, int debug_info, FILE *fp, const char *initname)
+mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, const char *initname)
{
uint8_t *bin = NULL;
size_t bin_size = 0, bin_idx = 0;
@@ -524,12 +858,12 @@ mrb_dump_irep_cfunc(mrb_state *mrb, size_t start_index, int debug_info, FILE *fp
return MRB_DUMP_INVALID_ARGUMENT;
}
- result = mrb_dump_irep(mrb, start_index, debug_info, &bin, &bin_size);
+ result = dump_irep(mrb, irep, debug_info, &bin, &bin_size);
if (result == MRB_DUMP_OK) {
- fprintf(fp, "#include <stdint.h>\n"); // for uint8_t under at least Darwin
+ fprintf(fp, "#include <stdint.h>\n"); /* for uint8_t under at least Darwin */
fprintf(fp, "const uint8_t %s[] = {", initname);
while (bin_idx < bin_size) {
- if (bin_idx % 16 == 0 ) fputs("\n", fp);
+ if (bin_idx % 16 == 0) fputs("\n", fp);
fprintf(fp, "0x%02x,", bin[bin_idx++]);
}
fputs("\n};\n", fp);
diff --git a/src/error.c b/src/error.c
index df4bbc866..64851bb56 100644
--- a/src/error.c
+++ b/src/error.c
@@ -7,15 +7,15 @@
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <string.h>
#include "mruby.h"
#include "mruby/array.h"
-#include "mruby/class.h"
#include "mruby/irep.h"
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/variable.h"
-#include "error.h"
+#include "mruby/debug.h"
+#include "mruby/error.h"
+#include "mrb_throw.h"
mrb_value
mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
@@ -24,7 +24,7 @@ mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
}
mrb_value
-mrb_exc_new3(mrb_state *mrb, struct RClass* c, mrb_value str)
+mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
{
str = mrb_str_to_str(mrb, str);
return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, str);
@@ -44,7 +44,7 @@ exc_initialize(mrb_state *mrb, mrb_value exc)
mrb_value mesg;
if (mrb_get_args(mrb, "|o", &mesg) == 1) {
- mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), mesg);
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
}
return exc;
}
@@ -73,7 +73,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
if (argc == 0) return self;
if (mrb_obj_equal(mrb, self, a)) return self;
exc = mrb_obj_clone(mrb, self);
- mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), a);
+ mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
return exc;
}
@@ -89,7 +89,7 @@ exc_exception(mrb_state *mrb, mrb_value self)
static mrb_value
exc_to_s(mrb_state *mrb, mrb_value exc)
{
- mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
+ mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
if (mrb_nil_p(mesg)) return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
return mesg;
@@ -122,33 +122,35 @@ static mrb_value
exc_inspect(mrb_state *mrb, mrb_value exc)
{
mrb_value str, mesg, file, line;
+ mrb_bool append_mesg;
- mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
- file = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "file", 4));
- line = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "line", 4));
+ mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
+ file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
+ line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
+ append_mesg = !mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0;
if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
- str = file;
- mrb_str_cat(mrb, str, ":", 1);
+ str = mrb_str_dup(mrb, file);
+ mrb_str_cat_lit(mrb, str, ":");
mrb_str_append(mrb, str, line);
- mrb_str_cat(mrb, str, ": ", 2);
- if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
+ mrb_str_cat_lit(mrb, str, ": ");
+ if (append_mesg) {
mrb_str_append(mrb, str, mesg);
- mrb_str_cat(mrb, str, " (", 2);
+ mrb_str_cat_lit(mrb, str, " (");
}
mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
- if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
- mrb_str_cat(mrb, str, ")", 1);
+ if (append_mesg) {
+ mrb_str_cat_lit(mrb, str, ")");
}
}
else {
str = mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
- if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
- mrb_str_cat(mrb, str, ": ", 2);
+ if (append_mesg) {
+ mrb_str_cat_lit(mrb, str, ": ");
mrb_str_append(mrb, str, mesg);
}
else {
- mrb_str_cat(mrb, str, ": ", 2);
+ mrb_str_cat_lit(mrb, str, ": ");
mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
}
}
@@ -162,7 +164,7 @@ exc_equal(mrb_state *mrb, mrb_value exc)
mrb_value obj;
mrb_value mesg;
mrb_bool equal_p;
- mrb_sym id_mesg = mrb_intern2(mrb, "mesg", 4);
+ mrb_sym id_mesg = mrb_intern_lit(mrb, "mesg");
mrb_get_args(mrb, "o", &obj);
if (mrb_obj_equal(mrb, exc, obj)) {
@@ -170,7 +172,7 @@ exc_equal(mrb_state *mrb, mrb_value exc)
}
else {
if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
- if (mrb_respond_to(mrb, obj, mrb_intern2(mrb, "message", 7))) {
+ if (mrb_respond_to(mrb, obj, mrb_intern_lit(mrb, "message"))) {
mesg = mrb_funcall(mrb, obj, "message", 0);
}
else
@@ -192,15 +194,19 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
mrb_callinfo *ci = mrb->c->ci;
mrb_code *pc = ci->pc;
- mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->c->cibase));
- ci--;
+ mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->c->cibase));
while (ci >= mrb->c->cibase) {
- if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
+ mrb_code *err = ci->err;
+
+ if (!err && pc) err = pc - 1;
+ if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
mrb_irep *irep = ci->proc->body.irep;
- if (irep->filename && irep->lines && irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
- mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, irep->filename));
- mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
+ int32_t const line = mrb_debug_get_line(irep, err - irep->iseq);
+ char const* file = mrb_debug_get_filename(irep, err - irep->iseq);
+ if (line != -1 && file) {
+ mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
+ mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
return;
}
}
@@ -218,7 +224,7 @@ mrb_exc_raise(mrb_state *mrb, mrb_value exc)
mrb_p(mrb, exc);
abort();
}
- mrb_longjmp(mrb);
+ MRB_THROW(mrb->jmp);
}
void
@@ -226,7 +232,7 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
{
mrb_value mesg;
mesg = mrb_str_new_cstr(mrb, msg);
- mrb_exc_raise(mrb, mrb_exc_new3(mrb, c, mesg));
+ mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
}
mrb_value
@@ -292,7 +298,7 @@ mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
va_start(args, fmt);
mesg = mrb_vformat(mrb, fmt, args);
va_end(args);
- mrb_exc_raise(mrb, mrb_exc_new3(mrb, c, mesg));
+ mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
}
void
@@ -307,7 +313,7 @@ mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
va_end(args);
argv[1] = mrb_symbol_value(id);
- exc = mrb_class_new_instance(mrb, 2, argv, E_NAME_ERROR);
+ exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv);
mrb_exc_raise(mrb, exc);
}
@@ -342,21 +348,14 @@ mrb_bug(mrb_state *mrb, const char *fmt, ...)
exit(EXIT_FAILURE);
}
-int
-sysexit_status(mrb_state *mrb, mrb_value err)
-{
- mrb_value st = mrb_iv_get(mrb, err, mrb_intern2(mrb, "status", 6));
- return mrb_fixnum(st);
-}
-
static void
set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
{
mrb_funcall(mrb, info, "set_backtrace", 1, bt);
}
-mrb_value
-make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
+static mrb_value
+make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr)
{
mrb_value mesg;
int n;
@@ -371,7 +370,7 @@ make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
if (isstr) {
mesg = mrb_check_string_type(mrb, argv[0]);
if (!mrb_nil_p(mesg)) {
- mesg = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mesg);
+ mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mesg);
break;
}
}
@@ -383,7 +382,7 @@ make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
n = 1;
exception_call:
{
- mrb_sym exc = mrb_intern2(mrb, "exception", 9);
+ mrb_sym exc = mrb_intern_lit(mrb, "exception");
if (mrb_respond_to(mrb, argv[0], exc)) {
mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
}
@@ -409,7 +408,7 @@ exception_call:
}
mrb_value
-mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv)
+mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
{
return make_exception(mrb, argc, argv, TRUE);
}
@@ -448,6 +447,7 @@ mrb_init_exception(mrb_state *mrb)
mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE());
mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE());
+ mrb_define_method(mrb, e, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
diff --git a/src/error.h b/src/error.h
index 5aa4ca374..0e0dacf63 100644
--- a/src/error.h
+++ b/src/error.h
@@ -1,19 +1,3 @@
-/*
-** error.h - Exception class
-**
-** See Copyright Notice in mruby.h
-*/
-
-#ifndef MRUBY_ERROR_H
-#define MRUBY_ERROR_H
-
-void mrb_sys_fail(mrb_state *mrb, const char *mesg);
-int sysexit_status(mrb_state *mrb, mrb_value err);
-mrb_value mrb_exc_new3(mrb_state *mrb, struct RClass* c, mrb_value str);
-mrb_value make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr);
-mrb_value mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv);
-mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
-void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
-void mrb_longjmp(mrb_state *mrb);
-
-#endif /* MRUBY_ERROR_H */
+/* this header file is to be removed soon.
+ added for compatibility purpose (1.0.0) */
+#include "mruby/error.h"
diff --git a/src/etc.c b/src/etc.c
index 2aee0f0f7..8398aeebd 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -6,9 +6,8 @@
#include "mruby.h"
#include "mruby/string.h"
-#include "error.h"
-#include "mruby/numeric.h"
#include "mruby/data.h"
+#include "mruby/class.h"
struct RData*
mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
@@ -17,7 +16,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb
data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass);
data->data = ptr;
- data->type = (mrb_data_type*) type;
+ data->type = type;
return data;
}
@@ -35,18 +34,17 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
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));
}
- }
-}
+ else {
+ struct RClass *c = mrb_class(mrb, obj);
-void *
-mrb_data_check_and_get(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
-{
- mrb_data_check_type(mrb, obj, type);
- return DATA_PTR(obj);
+ mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)",
+ mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name));
+ }
+ }
}
void *
-mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
+mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
if (mrb_special_const_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) {
return NULL;
@@ -57,32 +55,11 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
return DATA_PTR(obj);
}
-mrb_value
-mrb_lastline_get(mrb_state *mrb)
-{
- mrb_value *argv;
- int argc;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- if (argc < 1) {
- return mrb_nil_value();
- }
- else
- {
- return argv[0];
- }
-}
-
-/* ------------------------------------------------ */
-/*
- * Calls func(obj, arg, recursive), where recursive is non-zero if the
- * current method is called recursively on obj
- */
-
-mrb_value
-mrb_exec_recursive(mrb_state *mrb, mrb_value (*func) (mrb_state *, mrb_value, mrb_value, int), mrb_value obj, void *arg)
+void *
+mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
- return func(mrb, obj, *(mrb_value*)arg, 0);
+ mrb_data_check_type(mrb, obj, type);
+ return DATA_PTR(obj);
}
mrb_sym
@@ -104,26 +81,13 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
name = mrb_str_intern(mrb, name);
/* fall through */
case MRB_TT_SYMBOL:
- return mrb_symbol(name);
+ id = mrb_symbol(name);
}
return id;
}
-/*
- * call-seq:
- * proc { |...| block } -> a_proc
- *
- * Equivalent to <code>Proc.new</code>.
- */
-
-mrb_value
-mrb_block_proc(void)
-{
- return mrb_nil_value();
-}
-
-static mrb_int
-float_id(mrb_float f)
+mrb_int
+mrb_float_id(mrb_float f)
{
const char *p = (const char*)&f;
int len = sizeof(f);
@@ -159,9 +123,9 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_SYMBOL:
return MakeID(mrb_symbol(obj));
case MRB_TT_FIXNUM:
- return MakeID2(float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
+ return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
case MRB_TT_FLOAT:
- return MakeID(float_id(mrb_float(obj)));
+ return MakeID(mrb_float_id(mrb_float(obj)));
case MRB_TT_STRING:
case MRB_TT_OBJECT:
case MRB_TT_CLASS:
@@ -176,7 +140,7 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_FILE:
case MRB_TT_DATA:
default:
- return MakeID(obj.value.p);
+ return MakeID(mrb_ptr(obj));
}
}
@@ -192,11 +156,21 @@ mrb_float_value(mrb_state *mrb, mrb_float f)
}
mrb_value
-mrb_voidp_value(mrb_state *mrb, void *p)
+mrb_float_pool(mrb_state *mrb, mrb_float f)
+{
+ struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat));
+ nf->tt = MRB_TT_FLOAT;
+ nf->c = mrb->float_class;
+ nf->f = f;
+ return mrb_obj_value(nf);
+}
+
+mrb_value
+mrb_cptr_value(mrb_state *mrb, void *p)
{
mrb_value v;
- v.value.p = mrb_obj_alloc(mrb, MRB_TT_VOIDP, mrb->object_class);
+ v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class);
v.value.vp->p = p;
return v;
}
diff --git a/src/gc.c b/src/gc.c
index 8569cc085..4db640ff4 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -4,12 +4,6 @@
** See Copyright Notice in mruby.h
*/
-#ifndef SIZE_MAX
- /* Some versions of VC++
- * has SIZE_MAX in stdint.h
- */
-# include <limits.h>
-#endif
#include <string.h>
#include <stdlib.h>
#include "mruby.h"
@@ -28,11 +22,11 @@
mruby's GC is Tri-color Incremental GC with Mark & Sweep.
Algorithm details are omitted.
- Instead, the part about the implementation described below.
+ Instead, the implementation part is described below.
== Object's Color
- Each object to be painted in three colors.
+ Each object can be painted in three colors:
* White - Unmarked.
* Gray - Marked, But the child objects are unmarked.
@@ -68,9 +62,9 @@
== Write Barrier
- mruby implementer, C extension library writer must write a write
+ mruby implementer and C extension library writer must write a write
barrier when writing a pointer to an object on object's field.
- Two different write barrier:
+ Two different write barrier are available:
* mrb_field_write_barrier
* mrb_write_barrier
@@ -88,6 +82,9 @@
* Major GC - same as a full regular GC cycle.
+ The difference to a "traditional" generational GC is, that the major GC
+ in mruby is triggered incrementally in a tri-color manner.
+
For details, see the comments for each function.
@@ -144,9 +141,9 @@ gettimeofday_time(void)
gc_time = gettimeofday_time() - gc_time;\
gc_total_time += gc_time;\
fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
- fprintf(stderr, "live: %d\n", mrb->live);\
- fprintf(stderr, "majorgc_old_threshold: %d\n", mrb->majorgc_old_threshold);\
- fprintf(stderr, "gc_threshold: %d\n", mrb->gc_threshold);\
+ fprintf(stderr, "live: %zu\n", mrb->live);\
+ fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
+ fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
} while(0)
@@ -334,8 +331,10 @@ mrb_init_heap(mrb_state *mrb)
add_heap(mrb);
mrb->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
mrb->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
+#ifndef MRB_GC_TURN_OFF_GENERATIONAL
mrb->is_generational_gc_mode = TRUE;
mrb->gc_full = TRUE;
+#endif
#ifdef GC_PROFILE
program_invoke_time = gettimeofday_time();
@@ -365,11 +364,19 @@ mrb_free_heap(mrb_state *mrb)
static void
gc_protect(mrb_state *mrb, struct RBasic *p)
{
- if (mrb->arena_idx >= MRB_ARENA_SIZE) {
+#ifdef MRB_GC_FIXED_ARENA
+ if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) {
/* arena overflow error */
- mrb->arena_idx = MRB_ARENA_SIZE - 4; /* force room in arena */
+ mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
}
+#else
+ if (mrb->arena_idx >= mrb->arena_capa) {
+ /* extend arena */
+ mrb->arena_capa *= 1.5;
+ mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa);
+ }
+#endif
mrb->arena[mrb->arena_idx++] = p;
}
@@ -453,13 +460,15 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
for (i=0; i<e; i++) {
mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
}
- /* mark closure */
- for (ci = c->cibase; ci <= c->ci; ci++) {
- if (!ci) continue;
- mrb_gc_mark(mrb, (struct RBasic*)ci->env);
- mrb_gc_mark(mrb, (struct RBasic*)ci->proc);
- mrb_gc_mark(mrb, (struct RBasic*)ci->target_class);
+ /* mark VM stack */
+ if (c->cibase) {
+ for (ci = c->cibase; ci <= c->ci; ci++) {
+ mrb_gc_mark(mrb, (struct RBasic*)ci->env);
+ mrb_gc_mark(mrb, (struct RBasic*)ci->proc);
+ mrb_gc_mark(mrb, (struct RBasic*)ci->target_class);
+ }
}
+ /* mark fibers */
if (c->prev && c->prev->fib) {
mrb_gc_mark(mrb, (struct RBasic*)c->prev->fib);
}
@@ -506,10 +515,10 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
{
struct REnv *e = (struct REnv*)obj;
- if (e->cioff < 0) {
+ if (!MRB_ENV_STACK_SHARED_P(e)) {
int i, len;
- len = (int)e->flags;
+ len = (int)MRB_ENV_STACK_LEN(e);
for (i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
}
@@ -603,7 +612,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
{
struct REnv *e = (struct REnv*)obj;
- if (e->cioff < 0) {
+ if (!MRB_ENV_STACK_SHARED_P(e)) {
mrb_free(mrb, e->stack);
e->stack = NULL;
}
@@ -614,7 +623,8 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
- mrb_free_context(mrb, c);
+ if (c != mrb->root_c)
+ mrb_free_context(mrb, c);
}
break;
@@ -634,6 +644,16 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
mrb_gc_free_str(mrb, (struct RString*)obj);
break;
+ case MRB_TT_PROC:
+ {
+ struct RProc *p = (struct RProc*)obj;
+
+ if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
+ mrb_irep_decref(mrb, p->body.irep);
+ }
+ }
+ break;
+
case MRB_TT_RANGE:
mrb_free(mrb, ((struct RRange*)obj)->edges);
break;
@@ -641,7 +661,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
case MRB_TT_DATA:
{
struct RData *d = (struct RData*)obj;
- if (d->type->dfree) {
+ if (d->type && d->type->dfree) {
d->type->dfree(mrb, d->data);
}
mrb_gc_free_iv(mrb, (struct RObject*)obj);
@@ -657,7 +677,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
static void
root_scan_phase(mrb_state *mrb)
{
- size_t i, e, j;
+ size_t i, e;
if (!is_minor_gc(mrb)) {
mrb->gray_list = NULL;
@@ -677,17 +697,11 @@ root_scan_phase(mrb_state *mrb)
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
mark_context(mrb, mrb->root_c);
- /* mark irep pool */
- if (mrb->irep) {
- size_t len = mrb->irep_len;
- if (len > mrb->irep_capa) len = mrb->irep_capa;
- for (i=0; i<len; i++) {
- mrb_irep *irep = mrb->irep[i];
- if (!irep) continue;
- for (j=0; j<irep->plen; j++) {
- mrb_gc_mark_value(mrb, irep->pool[j]);
- }
- }
+ if (mrb->root_c->fib) {
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->root_c->fib);
+ }
+ if (mrb->root_c != mrb->c) {
+ mark_context(mrb, mrb->c);
}
}
@@ -825,13 +839,13 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
RVALUE *p = page->objects;
RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
size_t freed = 0;
- int dead_slot = 1;
+ mrb_bool dead_slot = TRUE;
int full = (page->freelist == NULL);
if (is_minor_gc(mrb) && page->old) {
/* skip a slot which doesn't contain any young object */
p = e;
- dead_slot = 0;
+ dead_slot = FALSE;
}
while (p<e) {
if (is_dead(mrb, &p->as.basic)) {
@@ -938,14 +952,19 @@ clear_all_old(mrb_state *mrb)
mrb_assert(is_generational(mrb));
if (is_major_gc(mrb)) {
+ /* finish the half baked GC */
incremental_gc_until(mrb, GC_STATE_NONE);
}
+ /* Sweep the dead objects, then reset all the live objects
+ * (including all the old objects, of course) to white. */
mrb->is_generational_gc_mode = FALSE;
prepare_incremental_sweep(mrb);
incremental_gc_until(mrb, GC_STATE_NONE);
- mrb->atomic_gray_list = mrb->gray_list = NULL;
mrb->is_generational_gc_mode = origin_mode;
+
+ /* The gray objects has already been painted as white */
+ mrb->atomic_gray_list = mrb->gray_list = NULL;
}
void
@@ -993,16 +1012,15 @@ mrb_full_gc(mrb_state *mrb)
GC_INVOKE_TIME_REPORT("mrb_full_gc()");
GC_TIME_START;
- if (mrb->gc_state == GC_STATE_SWEEP) {
- /* finish sweep phase */
- incremental_gc_until(mrb, GC_STATE_NONE);
- }
-
- /* clean all black object as old */
if (is_generational(mrb)) {
+ /* clear all the old objects back to young */
clear_all_old(mrb);
mrb->gc_full = TRUE;
}
+ else if (mrb->gc_state != GC_STATE_NONE) {
+ /* finish half baked GC cycle */
+ incremental_gc_until(mrb, GC_STATE_NONE);
+ }
incremental_gc_until(mrb, GC_STATE_NONE);
mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
@@ -1030,6 +1048,20 @@ mrb_gc_arena_save(mrb_state *mrb)
void
mrb_gc_arena_restore(mrb_state *mrb, int idx)
{
+#ifndef MRB_GC_FIXED_ARENA
+ int capa = mrb->arena_capa;
+
+ if (idx < capa / 2) {
+ capa *= 0.66;
+ if (capa < MRB_GC_ARENA_SIZE) {
+ capa = MRB_GC_ARENA_SIZE;
+ }
+ if (capa != mrb->arena_capa) {
+ mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa);
+ mrb->arena_capa = capa;
+ }
+ }
+#endif
mrb->arena_idx = idx;
}
@@ -1254,21 +1286,21 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
}
void
-mrb_objspace_each_objects(mrb_state *mrb, each_object_callback* callback, void *data)
+mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
{
- struct heap_page* page = mrb->heaps;
+ struct heap_page* page = mrb->heaps;
- while (page != NULL) {
- RVALUE *p, *pend;
+ while (page != NULL) {
+ RVALUE *p, *pend;
- p = page->objects;
- pend = p + MRB_HEAP_PAGE_SIZE;
- for (;p < pend; p++) {
- (*callback)(mrb, &p->as.basic, data);
- }
-
- page = page->next;
+ p = page->objects;
+ pend = p + MRB_HEAP_PAGE_SIZE;
+ for (;p < pend; p++) {
+ (*callback)(mrb, &p->as.basic, data);
}
+
+ page = page->next;
+ }
}
#ifdef GC_TEST
@@ -1311,7 +1343,7 @@ test_mrb_field_write_barrier(void)
puts("test_mrb_field_write_barrier");
mrb->is_generational_gc_mode = FALSE;
obj = mrb_basic_ptr(mrb_ary_new(mrb));
- value = mrb_basic_ptr(mrb_str_new_cstr(mrb, "value"));
+ value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value"));
paint_black(obj);
paint_partial_white(mrb,value);
@@ -1353,7 +1385,7 @@ test_mrb_field_write_barrier(void)
{
puts("test_mrb_field_write_barrier_value");
obj = mrb_basic_ptr(mrb_ary_new(mrb));
- mrb_value value = mrb_str_new_cstr(mrb, "value");
+ mrb_value value = mrb_str_new_lit(mrb, "value");
paint_black(obj);
paint_partial_white(mrb, mrb_basic_ptr(value));
@@ -1402,12 +1434,12 @@ test_add_gray_list(void)
puts("test_add_gray_list");
change_gen_gc_mode(mrb, FALSE);
mrb_assert(mrb->gray_list == NULL);
- obj1 = mrb_basic_ptr(mrb_str_new_cstr(mrb, "test"));
+ obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
add_gray_list(mrb, obj1);
mrb_assert(mrb->gray_list == obj1);
mrb_assert(is_gray(obj1));
- obj2 = mrb_basic_ptr(mrb_str_new_cstr(mrb, "test"));
+ obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
add_gray_list(mrb, obj2);
mrb_assert(mrb->gray_list == obj2);
mrb_assert(mrb->gray_list->gcnext == obj1);
@@ -1435,7 +1467,7 @@ test_gc_gray_mark(void)
puts(" in MRB_TT_ARRAY");
obj_v = mrb_ary_new(mrb);
- value_v = mrb_str_new_cstr(mrb, "test");
+ value_v = mrb_str_new_lit(mrb, "test");
paint_gray(mrb_basic_ptr(obj_v));
paint_partial_white(mrb, mrb_basic_ptr(value_v));
mrb_ary_push(mrb, obj_v, value_v);
@@ -1560,5 +1592,5 @@ gc_test(mrb_state *mrb, mrb_value self)
test_incremental_sweep_phase();
return mrb_nil_value();
}
-#endif
-#endif
+#endif /* GC_DEBUG */
+#endif /* GC_TEST */
diff --git a/src/hash.c b/src/hash.c
index 1ffaed5fb..c39560d5c 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -12,25 +12,92 @@
#include "mruby/string.h"
#include "mruby/variable.h"
+/* a function to get hash value of a float number */
+mrb_int mrb_float_id(mrb_float f);
+
static inline khint_t
mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
{
- khint_t h = (khint_t)mrb_type(key) << 24;
- mrb_value h2;
+ enum mrb_vtype t = mrb_type(key);
+ mrb_value hv;
+ const char *p;
+ mrb_int i, len;
+ khint_t h;
+
+ switch (t) {
+ case MRB_TT_STRING:
+ p = RSTRING_PTR(key);
+ len = RSTRING_LEN(key);
+ h = 0;
+ for (i=0; i<len; i++) {
+ h = (h << 5) - h + *p++;
+ }
+ return h;
- h2 = mrb_funcall(mrb, key, "hash", 0, 0);
- h ^= h2.value.i;
- return h;
+ case MRB_TT_SYMBOL:
+ h = (khint_t)mrb_symbol(key);
+ return kh_int_hash_func(mrb,h);
+
+ case MRB_TT_FIXNUM:
+ h = (khint_t)mrb_float_id((mrb_float)mrb_fixnum(key));
+ return kh_int_hash_func(mrb,h);
+
+ case MRB_TT_FLOAT:
+ h = (khint_t)mrb_float_id(mrb_float(key));
+ return kh_int_hash_func(mrb,h);
+
+ default:
+ hv = mrb_funcall(mrb, key, "hash", 0);
+ h = (khint_t)t ^ mrb_fixnum(hv);
+ return kh_int_hash_func(mrb,h);
+ }
}
static inline khint_t
mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
{
- return mrb_eql(mrb, a, b);
+ enum mrb_vtype t = mrb_type(a);
+
+ switch (t) {
+ case MRB_TT_STRING:
+ return mrb_str_equal(mrb, a, b);
+
+ case MRB_TT_SYMBOL:
+ if (mrb_type(b) != MRB_TT_SYMBOL) return FALSE;
+ return mrb_symbol(a) == mrb_symbol(b);
+
+ case MRB_TT_FIXNUM:
+ switch (mrb_type(b)) {
+ case MRB_TT_FIXNUM:
+ return mrb_fixnum(a) == mrb_fixnum(b);
+ case MRB_TT_FLOAT:
+ return (mrb_float)mrb_fixnum(a) == mrb_float(b);
+ default:
+ return FALSE;
+ }
+
+ case MRB_TT_FLOAT:
+ switch (mrb_type(b)) {
+ case MRB_TT_FIXNUM:
+ return mrb_float(a) == (mrb_float)mrb_fixnum(b);
+ case MRB_TT_FLOAT:
+ return mrb_float(a) == mrb_float(b);
+ default:
+ return FALSE;
+ }
+
+ default:
+ return mrb_eql(mrb, a, b);
+ }
}
-KHASH_DECLARE(ht, mrb_value, mrb_value, 1)
-KHASH_DEFINE (ht, mrb_value, mrb_value, 1, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal)
+typedef struct {
+ mrb_value v;
+ mrb_int n;
+} mrb_hash_value;
+
+KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
+KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal)
static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
@@ -55,7 +122,7 @@ mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash)
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
mrb_value key = kh_key(h, k);
- mrb_value val = kh_value(h, k);
+ mrb_value val = kh_value(h, k).v;
mrb_gc_mark_value(mrb, key);
mrb_gc_mark_value(mrb, val);
@@ -73,7 +140,7 @@ mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash)
void
mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
{
- if (hash->ht) kh_destroy(ht, hash->ht);
+ if (hash->ht) kh_destroy(ht, mrb, hash->ht);
}
@@ -85,7 +152,7 @@ mrb_hash_new_capa(mrb_state *mrb, int capa)
h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
h->ht = kh_init(ht, mrb);
if (capa > 0) {
- kh_resize(ht, h->ht, capa);
+ kh_resize(ht, mrb, h->ht, capa);
}
h->iv = 0;
return mrb_obj_value(h);
@@ -104,9 +171,9 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
khiter_t k;
if (h) {
- k = kh_get(ht, h, key);
+ k = kh_get(ht, mrb, h, key);
if (k != kh_end(h))
- return kh_value(h, k);
+ return kh_value(h, k).v;
}
/* not found */
@@ -123,9 +190,9 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
khiter_t k;
if (h) {
- k = kh_get(ht, h, key);
+ k = kh_get(ht, mrb, h, key);
if (k != kh_end(h))
- return kh_value(h, k);
+ return kh_value(h, k).v;
}
/* not found */
@@ -133,29 +200,32 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
}
void
-mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) /* mrb_hash_aset */
+mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
{
khash_t(ht) *h;
khiter_t k;
+ int r;
mrb_hash_modify(mrb, hash);
h = RHASH_TBL(hash);
if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb);
- k = kh_get(ht, h, key);
- if (k == kh_end(h)) {
+ k = kh_put2(ht, mrb, h, key, &r);
+ kh_value(h, k).v = val;
+
+ if (r != 0) {
/* expand */
int ai = mrb_gc_arena_save(mrb);
- k = kh_put(ht, h, KEY(key));
+ kh_key(h, k) = KEY(key);
mrb_gc_arena_restore(mrb, ai);
+ kh_value(h, k).n = kh_size(h)-1;
}
- kh_value(h, k) = val;
mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash));
return;
}
-mrb_value
+static mrb_value
mrb_hash_dup(mrb_state *mrb, mrb_value hash)
{
struct RHash* ret;
@@ -172,7 +242,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h,k)) {
int ai = mrb_gc_arena_save(mrb);
- ret_k = kh_put(ht, ret_h, KEY(kh_key(h,k)));
+ ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h,k)));
mrb_gc_arena_restore(mrb, ai);
kh_val(ret_h, ret_k) = kh_val(h,k);
}
@@ -242,69 +312,25 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash)
*/
static mrb_value
-mrb_hash_init_core(mrb_state *mrb, mrb_value hash)
+mrb_hash_init(mrb_state *mrb, mrb_value hash)
{
mrb_value block, ifnone;
- mrb_value *argv;
- int argc;
+ mrb_bool ifnone_p;
- mrb_get_args(mrb, "o*", &block, &argv, &argc);
+ ifnone = mrb_nil_value();
+ mrb_get_args(mrb, "&|o?", &block, &ifnone, &ifnone_p);
mrb_hash_modify(mrb, hash);
- if (mrb_nil_p(block)) {
- if (argc > 0) {
- if (argc != 1) mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
- ifnone = argv[0];
- }
- else {
- ifnone = mrb_nil_value();
- }
- }
- else {
- if (argc > 0) {
+ if (!mrb_nil_p(block)) {
+ if (ifnone_p) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
}
RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
ifnone = block;
}
- mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
+ mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
return hash;
}
-/*
- * call-seq:
- * Hash[ key, value, ... ] -> new_hash
- * Hash[ [ [key, value], ... ] ] -> new_hash
- * Hash[ object ] -> new_hash
- *
- * Creates a new hash populated with the given objects. Equivalent to
- * the literal <code>{ <i>key</i> => <i>value</i>, ... }</code>. In the first
- * form, keys and values occur in pairs, so there must be an even number of arguments.
- * The second and third form take a single argument which is either
- * an array of key-value pairs or an object convertible to a hash.
- *
- * Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}
- * Hash[ [ ["a", 100], ["b", 200] ] ] #=> {"a"=>100, "b"=>200}
- * Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200}
- */
-
-static mrb_value
-to_hash(mrb_state *mrb, mrb_value hash)
-{
- return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash");
-}
-
-/*
- * call-seq:
- * Hash.try_convert(obj) -> hash or nil
- *
- * Try to convert <i>obj</i> into a hash, using to_hash method.
- * Returns converted hash or nil if <i>obj</i> cannot be converted
- * for any reason.
- *
- * Hash.try_convert({1=>2}) # => {1=>2}
- * Hash.try_convert("1=>2") # => nil
- */
-
/* 15.2.13.4.2 */
/*
* call-seq:
@@ -319,7 +345,7 @@ to_hash(mrb_state *mrb, mrb_value hash)
* h["c"] #=> nil
*
*/
-mrb_value
+static mrb_value
mrb_hash_aget(mrb_state *mrb, mrb_value self)
{
mrb_value key;
@@ -328,35 +354,6 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
return mrb_hash_get(mrb, self, key);
}
-/*
- * call-seq:
- * hsh.fetch(key [, default] ) -> obj
- * hsh.fetch(key) {| key | block } -> obj
- *
- * Returns a value from the hash for the given key. If the key can't be
- * found, there are several options: With no other arguments, it will
- * raise an <code>KeyError</code> exception; if <i>default</i> is
- * given, then that will be returned; if the optional code block is
- * specified, then that will be run and its result returned.
- *
- * h = { "a" => 100, "b" => 200 }
- * h.fetch("a") #=> 100
- * h.fetch("z", "go fish") #=> "go fish"
- * h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
- *
- * The following example shows that an exception is raised if the key
- * is not found and a default value is not supplied.
- *
- * h = { "a" => 100, "b" => 200 }
- * h.fetch("z")
- *
- * <em>produces:</em>
- *
- * prog.rb:2:in `fetch': key not found (KeyError)
- * from prog.rb:2
- *
- */
-
/* 15.2.13.4.5 */
/*
* call-seq:
@@ -382,14 +379,12 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_hash_default(mrb_state *mrb, mrb_value hash)
{
- mrb_value *argv;
- int argc;
mrb_value key;
+ mrb_bool given;
- mrb_get_args(mrb, "*", &argv, &argc);
+ mrb_get_args(mrb, "|o?", &key, &given);
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- if (argc == 0) return mrb_nil_value();
- key = argv[0];
+ if (!given) return mrb_nil_value();
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
else {
@@ -425,7 +420,7 @@ mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
mrb_get_args(mrb, "o", &ifnone);
mrb_hash_modify(mrb, hash);
- mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
+ mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
RHASH(hash)->flags &= ~(MRB_HASH_PROC_DEFAULT);
return ifnone;
@@ -476,7 +471,7 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
mrb_get_args(mrb, "o", &ifnone);
mrb_hash_modify(mrb, hash);
- mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
+ mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
return ifnone;
@@ -488,12 +483,18 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
mrb_value delVal;
+ mrb_int n;
if (h) {
- k = kh_get(ht, h, key);
+ k = kh_get(ht, mrb, h, key);
if (k != kh_end(h)) {
- delVal = kh_value(h, k);
- kh_del(ht, h, k);
+ delVal = kh_value(h, k).v;
+ n = kh_value(h, k).n;
+ kh_del(ht, mrb, h, k);
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
+ if (kh_value(h, k).n > n) kh_value(h, k).n--;
+ }
return delVal;
}
}
@@ -520,7 +521,7 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
* h.delete("z") { |el| "#{el} not found" } #=> "z not found"
*
*/
-mrb_value
+static mrb_value
mrb_hash_delete(mrb_state *mrb, mrb_value self)
{
mrb_value key;
@@ -574,75 +575,6 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
}
}
-/*
- * call-seq:
- * hsh.delete_if {| key, value | block } -> hsh
- * hsh.delete_if -> an_enumerator
- *
- * Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
- * evaluates to <code>true</code>.
- *
- * If no block is given, an enumerator is returned instead.
- *
- * h = { "a" => 100, "b" => 200, "c" => 300 }
- * h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
- *
- */
-
-/*
- * call-seq:
- * hsh.reject! {| key, value | block } -> hsh or nil
- * hsh.reject! -> an_enumerator
- *
- * Equivalent to <code>Hash#delete_if</code>, but returns
- * <code>nil</code> if no changes were made.
- */
-
-/*
- * call-seq:
- * hsh.reject {| key, value | block } -> a_hash
- *
- * Same as <code>Hash#delete_if</code>, but works on (and returns) a
- * copy of the <i>hsh</i>. Equivalent to
- * <code><i>hsh</i>.dup.delete_if</code>.
- *
- */
-
-/*
- * call-seq:
- * hsh.select {|key, value| block} -> a_hash
- * hsh.select -> an_enumerator
- *
- * Returns a new hash consisting of entries for which the block returns true.
- *
- * If no block is given, an enumerator is returned instead.
- *
- * h = { "a" => 100, "b" => 200, "c" => 300 }
- * h.select {|k,v| k > "a"} #=> {"b" => 200, "c" => 300}
- * h.select {|k,v| v < 200} #=> {"a" => 100}
- */
-
-/*
- * call-seq:
- * hsh.select! {| key, value | block } -> hsh or nil
- * hsh.select! -> an_enumerator
- *
- * Equivalent to <code>Hash#keep_if</code>, but returns
- * <code>nil</code> if no changes were made.
- */
-
-/*
- * call-seq:
- * hsh.keep_if {| key, value | block } -> hsh
- * hsh.keep_if -> an_enumerator
- *
- * Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
- * evaluates to false.
- *
- * If no block is given, an enumerator is returned instead.
- *
- */
-
/* 15.2.13.4.4 */
/*
* call-seq:
@@ -660,7 +592,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
- if (h) kh_clear(ht, h);
+ if (h) kh_clear(ht, mrb, h);
return hash;
}
@@ -683,7 +615,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
* h #=> {"a"=>9, "b"=>200, "c"=>4}
*
*/
-mrb_value
+static mrb_value
mrb_hash_aset(mrb_state *mrb, mrb_value self)
{
mrb_value key, val;
@@ -693,52 +625,6 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
return val;
}
-/* 15.2.13.4.17 */
-/* 15.2.13.4.23 */
-/*
- * call-seq:
- * hsh.replace(other_hash) -> hsh
- *
- * Replaces the contents of <i>hsh</i> with the contents of
- * <i>other_hash</i>.
- *
- * h = { "a" => 100, "b" => 200 }
- * h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
- *
- */
-
-static mrb_value
-mrb_hash_replace(mrb_state *mrb, mrb_value hash)
-{
- mrb_value hash2, ifnone;
- khash_t(ht) *h2;
- khiter_t k;
-
- mrb_get_args(mrb, "o", &hash2);
- hash2 = to_hash(mrb, hash2);
- if (mrb_obj_equal(mrb, hash, hash2)) return hash;
- mrb_hash_clear(mrb, hash);
-
- h2 = RHASH_TBL(hash2);
- if (h2) {
- for (k = kh_begin(h2); k != kh_end(h2); k++) {
- if (kh_exist(h2, k))
- mrb_hash_set(mrb, hash, kh_key(h2, k), kh_value(h2, k));
- }
- }
-
- if (MRB_RHASH_PROCDEFAULT_P(hash2)) {
- RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
- ifnone = RHASH_PROCDEFAULT(hash2);
- }
- else {
- ifnone = RHASH_IFNONE(hash2);
- }
- mrb_iv_set(mrb, hash, mrb_intern2(mrb, "ifnone", 6), ifnone);
-
- return hash;
-}
-
/* 15.2.13.4.20 */
/* 15.2.13.4.25 */
/*
@@ -781,62 +667,6 @@ mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
return mrb_true_value();
}
-static mrb_value
-inspect_hash(mrb_state *mrb, mrb_value hash, int recur)
-{
- mrb_value str, str2;
- khash_t(ht) *h = RHASH_TBL(hash);
- khiter_t k;
-
- if (recur) return mrb_str_new(mrb, "{...}", 5);
-
- str = mrb_str_new(mrb, "{", 1);
- if (h && kh_size(h) > 0) {
- for (k = kh_begin(h); k != kh_end(h); k++) {
- int ai;
-
- if (!kh_exist(h,k)) continue;
-
- ai = mrb_gc_arena_save(mrb);
-
- if (RSTRING_LEN(str) > 1) mrb_str_cat(mrb, str, ", ", 2);
-
- str2 = mrb_inspect(mrb, kh_key(h,k));
- mrb_str_append(mrb, str, str2);
- mrb_str_buf_cat(mrb, str, "=>", 2);
- str2 = mrb_inspect(mrb, kh_value(h,k));
- mrb_str_append(mrb, str, str2);
-
- mrb_gc_arena_restore(mrb, ai);
- }
- }
- mrb_str_buf_cat(mrb, str, "}", 1);
-
- return str;
-}
-
-/* 15.2.13.4.30 (x)*/
-/*
- * call-seq:
- * hsh.to_s -> string
- * hsh.inspect -> string
- *
- * Return the contents of this hash as a string.
- *
- * h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
- * h.to_s #=> "{\"c\"=>300, \"a\"=>100, \"d\"=>400}"
- */
-
-static mrb_value
-mrb_hash_inspect(mrb_state *mrb, mrb_value hash)
-{
- khash_t(ht) *h = RHASH_TBL(hash);
-
- if (!h || kh_size(h) == 0)
- return mrb_str_new(mrb, "{}", 2);
- return inspect_hash(mrb, hash, 0);
-}
-
/* 15.2.13.4.29 (x)*/
/*
* call-seq:
@@ -869,14 +699,18 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
- mrb_value ary;
+ mrb_value ary, *p;
- if (!h) return mrb_ary_new(mrb);
+ if (!h || kh_size(h) == 0) return mrb_ary_new(mrb);
ary = mrb_ary_new_capa(mrb, kh_size(h));
+ mrb_ary_set(mrb, ary, kh_size(h)-1, mrb_nil_value());
+ p = RARRAY_PTR(ary);
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
- mrb_value v = kh_key(h,k);
- mrb_ary_push(mrb, ary, v);
+ mrb_value kv = kh_key(h,k);
+ mrb_hash_value hv = kh_value(h,k);
+
+ p[hv.n] = kv;
}
}
return ary;
@@ -906,26 +740,14 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
ary = mrb_ary_new_capa(mrb, kh_size(h));
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)){
- mrb_value v = kh_value(h,k);
- mrb_ary_push(mrb, ary, v);
+ mrb_hash_value hv = kh_value(h,k);
+
+ mrb_ary_set(mrb, ary, hv.n, hv.v);
}
}
return ary;
}
-static mrb_value
-mrb_hash_has_keyWithKey(mrb_state *mrb, mrb_value hash, mrb_value key)
-{
- khash_t(ht) *h = RHASH_TBL(hash);
- khiter_t k;
-
- if (h) {
- k = kh_get(ht, h, key);
- return mrb_bool_value(k != kh_end(h));
- }
- return mrb_false_value();
-}
-
/* 15.2.13.4.13 */
/* 15.2.13.4.15 */
/* 15.2.13.4.18 */
@@ -949,27 +771,16 @@ static mrb_value
mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
{
mrb_value key;
+ khash_t(ht) *h;
+ khiter_t k;
mrb_get_args(mrb, "o", &key);
- return mrb_hash_has_keyWithKey(mrb, hash, key);
-}
-
-static mrb_value
-mrb_hash_has_valueWithvalue(mrb_state *mrb, mrb_value hash, mrb_value value)
-{
- khash_t(ht) *h = RHASH_TBL(hash);
- khiter_t k;
+ h = RHASH_TBL(hash);
if (h) {
- for (k = kh_begin(h); k != kh_end(h); k++) {
- if (!kh_exist(h, k)) continue;
-
- if (mrb_equal(mrb, kh_value(h,k), value)) {
- return mrb_true_value();
- }
- }
+ k = kh_get(ht, mrb, h, key);
+ return mrb_bool_value(k != kh_end(h));
}
-
return mrb_false_value();
}
@@ -992,233 +803,24 @@ static mrb_value
mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
{
mrb_value val;
+ khash_t(ht) *h;
+ khiter_t k;
mrb_get_args(mrb, "o", &val);
- return mrb_hash_has_valueWithvalue(mrb, hash, val);
-}
+ h = RHASH_TBL(hash);
-static mrb_value
-hash_equal(mrb_state *mrb, mrb_value hash1, mrb_value hash2, int eql)
-{
- khash_t(ht) *h1, *h2;
+ if (h) {
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
- if (mrb_obj_equal(mrb, hash1, hash2)) return mrb_true_value();
- if (!mrb_hash_p(hash2)) {
- if (!mrb_respond_to(mrb, hash2, mrb_intern2(mrb, "to_hash", 7))) {
- return mrb_false_value();
- }
- if (eql)
- return mrb_fixnum_value(mrb_eql(mrb, hash2, hash1));
- else
- return mrb_fixnum_value(mrb_equal(mrb, hash2, hash1));
- }
- h1 = RHASH_TBL(hash1);
- h2 = RHASH_TBL(hash2);
- if (!h1) {
- return mrb_bool_value(!h2);
- }
- if (!h2) return mrb_false_value();
- if (kh_size(h1) != kh_size(h2)) return mrb_false_value();
- else {
- khiter_t k1, k2;
- mrb_value key;
-
- for (k1 = kh_begin(h1); k1 != kh_end(h1); k1++) {
- if (!kh_exist(h1, k1)) continue;
- key = kh_key(h1,k1);
- k2 = kh_get(ht, h2, key);
- if (k2 != kh_end(h2)) {
- if (mrb_equal(mrb, kh_value(h1,k1), kh_value(h2,k2))) {
- continue; /* next key */
- }
+ if (mrb_equal(mrb, kh_value(h,k).v, val)) {
+ return mrb_true_value();
}
- return mrb_false_value();
}
}
- return mrb_true_value();
-}
-
-/* 15.2.13.4.1 */
-/*
- * call-seq:
- * hsh == other_hash -> true or false
- *
- * Equality---Two hashes are equal if they each contain the same number
- * of keys and if each key-value pair is equal to (according to
- * <code>Object#==</code>) the corresponding elements in the other
- * hash.
- *
- * h1 = { "a" => 1, "c" => 2 }
- * h2 = { 7 => 35, "c" => 2, "a" => 1 }
- * h3 = { "a" => 1, "c" => 2, 7 => 35 }
- * h4 = { "a" => 1, "d" => 2, "f" => 35 }
- * h1 == h2 #=> false
- * h2 == h3 #=> true
- * h3 == h4 #=> false
- *
- */
-
-static mrb_value
-mrb_hash_equal(mrb_state *mrb, mrb_value hash1)
-{
- mrb_value hash2;
-
- mrb_get_args(mrb, "o", &hash2);
- return hash_equal(mrb, hash1, hash2, FALSE);
-}
-
-/* 15.2.13.4.32 (x)*/
-/*
- * call-seq:
- * hash.eql?(other) -> true or false
- *
- * Returns <code>true</code> if <i>hash</i> and <i>other</i> are
- * both hashes with the same content.
- */
-
-static mrb_value
-mrb_hash_eql(mrb_state *mrb, mrb_value hash1)
-{
- mrb_value hash2;
-
- mrb_get_args(mrb, "o", &hash2);
- return hash_equal(mrb, hash1, hash2, TRUE);
-}
-
-/*
- * call-seq:
- * hsh.merge!(other_hash) -> hsh
- * hsh.update(other_hash) -> hsh
- * hsh.merge!(other_hash){|key, oldval, newval| block} -> hsh
- * hsh.update(other_hash){|key, oldval, newval| block} -> hsh
- *
- * Adds the contents of <i>other_hash</i> to <i>hsh</i>. If no
- * block is specified, entries with duplicate keys are overwritten
- * with the values from <i>other_hash</i>, otherwise the value
- * of each duplicate key is determined by calling the block with
- * the key, its value in <i>hsh</i> and its value in <i>other_hash</i>.
- *
- * h1 = { "a" => 100, "b" => 200 }
- * h2 = { "b" => 254, "c" => 300 }
- * h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
- *
- * h1 = { "a" => 100, "b" => 200 }
- * h2 = { "b" => 254, "c" => 300 }
- * h1.merge!(h2) { |key, v1, v2| v1 }
- * #=> {"a"=>100, "b"=>200, "c"=>300}
- */
-
-/* 15.2.13.4.22 */
-/*
- * call-seq:
- * hsh.merge(other_hash) -> new_hash
- * hsh.merge(other_hash){|key, oldval, newval| block} -> new_hash
- *
- * Returns a new hash containing the contents of <i>other_hash</i> and
- * the contents of <i>hsh</i>. If no block is specified, the value for
- * entries with duplicate keys will be that of <i>other_hash</i>. Otherwise
- * the value for each duplicate key is determined by calling the block
- * with the key, its value in <i>hsh</i> and its value in <i>other_hash</i>.
- *
- * h1 = { "a" => 100, "b" => 200 }
- * h2 = { "b" => 254, "c" => 300 }
- * h1.merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
- * h1.merge(h2){|key, oldval, newval| newval - oldval}
- * #=> {"a"=>100, "b"=>54, "c"=>300}
- * h1 #=> {"a"=>100, "b"=>200}
- *
- */
-
-/*
- * call-seq:
- * hash.assoc(obj) -> an_array or nil
- *
- * Searches through the hash comparing _obj_ with the key using <code>==</code>.
- * Returns the key-value pair (two elements array) or +nil+
- * if no match is found. See <code>Array#assoc</code>.
- *
- * h = {"colors" => ["red", "blue", "green"],
- * "letters" => ["a", "b", "c" ]}
- * h.assoc("letters") #=> ["letters", ["a", "b", "c"]]
- * h.assoc("foo") #=> nil
- */
-
-mrb_value
-mrb_hash_assoc(mrb_state *mrb, mrb_value hash)
-{
- mrb_value key, value, has_key;
-
- mrb_get_args(mrb, "o", &key);
- if (mrb_nil_p(key))
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
-
- has_key = mrb_hash_has_keyWithKey(mrb, hash, key);
- if (mrb_test(has_key)) {
- value = mrb_hash_get(mrb, hash, key);
- return mrb_assoc_new(mrb, key, value);
- }
- else {
- return mrb_nil_value();
- }
-}
-
-/*
- * call-seq:
- * hash.rassoc(key) -> an_array or nil
- *
- * Searches through the hash comparing _obj_ with the value using <code>==</code>.
- * Returns the first key-value pair (two-element array) that matches. See
- * also <code>Array#rassoc</code>.
- *
- * a = {1=> "one", 2 => "two", 3 => "three", "ii" => "two"}
- * a.rassoc("two") #=> [2, "two"]
- * a.rassoc("four") #=> nil
- */
-
-mrb_value
-mrb_hash_rassoc(mrb_state *mrb, mrb_value hash)
-{
- mrb_value key, value, has_key;
-
- mrb_get_args(mrb, "o", &key);
- has_key = mrb_hash_has_keyWithKey(mrb, hash, key);
- if (mrb_test(has_key)) {
- value = mrb_hash_get(mrb, hash, key);
- return mrb_assoc_new(mrb, value, key);
- }
- else {
- return mrb_nil_value();
- }
+ return mrb_false_value();
}
-/*
- * call-seq:
- * hash.flatten -> an_array
- * hash.flatten(level) -> an_array
- *
- * Returns a new array that is a one-dimensional flattening of this
- * hash. That is, for every key or value that is an array, extract
- * its elements into the new array. Unlike Array#flatten, this
- * method does not flatten recursively by default. The optional
- * <i>level</i> argument determines the level of recursion to flatten.
- *
- * a = {1=> "one", 2 => [2,"two"], 3 => "three"}
- * a.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
- * a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
- */
-
-/*
- * A <code>Hash</code> is a collection of key-value pairs. It is
- * similar to an <code>Array</code>, except that indexing is done via
- * arbitrary keys of any object type, not an integer index. Hashes enumerate
- * their values in the order that the corresponding keys were inserted.
- *
- * Hashes have a <em>default value</em> that is returned when accessing
- * keys that do not exist in the hash. By default, that value is
- * <code>nil</code>.
- *
- */
-
void
mrb_init_hash(mrb_state *mrb)
{
@@ -1227,8 +829,6 @@ mrb_init_hash(mrb_state *mrb)
h = mrb->hash_class = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
MRB_SET_INSTANCE_TT(h, MRB_TT_HASH);
- mrb_include_module(mrb, h, mrb_class_get(mrb, "Enumerable"));
- mrb_define_method(mrb, h, "==", mrb_hash_equal, MRB_ARGS_REQ(1)); /* 15.2.13.4.1 */
mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */
mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */
mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */
@@ -1241,21 +841,17 @@ mrb_init_hash(mrb_state *mrb)
mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */
mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */
mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */
- mrb_define_method(mrb, h, "__init_core", mrb_hash_init_core, MRB_ARGS_ANY()); /* core of 15.2.13.4.16 */
- mrb_define_method(mrb, h, "initialize_copy", mrb_hash_replace, MRB_ARGS_REQ(1)); /* 15.2.13.4.17 */
+ mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)); /* 15.2.13.4.16 */
mrb_define_method(mrb, h, "key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.18 */
mrb_define_method(mrb, h, "keys", mrb_hash_keys, MRB_ARGS_NONE()); /* 15.2.13.4.19 */
mrb_define_method(mrb, h, "length", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.20 */
mrb_define_method(mrb, h, "member?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.21 */
- mrb_define_method(mrb, h, "replace", mrb_hash_replace, MRB_ARGS_REQ(1)); /* 15.2.13.4.23 */
mrb_define_method(mrb, h, "shift", mrb_hash_shift, MRB_ARGS_NONE()); /* 15.2.13.4.24 */
+ mrb_define_method(mrb, h, "dup", mrb_hash_dup, MRB_ARGS_NONE());
mrb_define_method(mrb, h, "size", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.25 */
mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */
mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */
mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */
mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/
- mrb_define_method(mrb, h, "inspect", mrb_hash_inspect, MRB_ARGS_NONE()); /* 15.2.13.4.30 (x)*/
- mrb_define_alias(mrb, h, "to_s", "inspect"); /* 15.2.13.4.31 (x)*/
- mrb_define_method(mrb, h, "eql?", mrb_hash_eql, MRB_ARGS_REQ(1)); /* 15.2.13.4.32 (x)*/
}
diff --git a/src/init.c b/src/init.c
index e97c72d68..c08c4b046 100644
--- a/src/init.c
+++ b/src/init.c
@@ -22,6 +22,7 @@ void mrb_init_numeric(mrb_state*);
void mrb_init_range(mrb_state*);
void mrb_init_gc(mrb_state*);
void mrb_init_math(mrb_state*);
+void mrb_init_version(mrb_state*);
void mrb_init_mrblib(mrb_state*);
void mrb_init_mrbgems(mrb_state*);
void mrb_final_mrbgems(mrb_state*);
@@ -47,6 +48,7 @@ mrb_init_core(mrb_state *mrb)
mrb_init_numeric(mrb); DONE;
mrb_init_range(mrb); DONE;
mrb_init_gc(mrb); DONE;
+ mrb_init_version(mrb); DONE;
mrb_init_mrblib(mrb); DONE;
#ifndef DISABLE_GEMS
mrb_init_mrbgems(mrb); DONE;
diff --git a/src/kernel.c b/src/kernel.c
index 4b426c6b4..d8a8e371f 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -10,29 +10,29 @@
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/variable.h"
-#include "error.h"
+#include "mruby/error.h"
typedef enum {
- NOEX_PUBLIC = 0x00,
- NOEX_NOSUPER = 0x01,
- NOEX_PRIVATE = 0x02,
- NOEX_PROTECTED = 0x04,
- NOEX_MASK = 0x06,
- NOEX_BASIC = 0x08,
- NOEX_UNDEF = NOEX_NOSUPER,
- NOEX_MODFUNC = 0x12,
- NOEX_SUPER = 0x20,
- NOEX_VCALL = 0x40,
- NOEX_RESPONDS = 0x80
+ NOEX_PUBLIC = 0x00,
+ NOEX_NOSUPER = 0x01,
+ NOEX_PRIVATE = 0x02,
+ NOEX_PROTECTED = 0x04,
+ NOEX_MASK = 0x06,
+ NOEX_BASIC = 0x08,
+ NOEX_UNDEF = NOEX_NOSUPER,
+ NOEX_MODFUNC = 0x12,
+ NOEX_SUPER = 0x20,
+ NOEX_VCALL = 0x40,
+ NOEX_RESPONDS = 0x80
} mrb_method_flag_t;
mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
- struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern2(mrb, "to_s", 4));
- if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
- return TRUE;
- return FALSE;
+ struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
+ if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
+ return TRUE;
+ return FALSE;
}
/* 15.3.1.3.17 */
@@ -157,36 +157,6 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(mrb_obj_id(self));
}
-/* 15.3.1.3.4 */
-/* 15.3.1.3.44 */
-/*
- * call-seq:
- * obj.send(symbol [, args...]) -> obj
- * obj.__send__(symbol [, args...]) -> obj
- *
- * Invokes the method identified by _symbol_, passing it any
- * arguments specified. You can use <code>__send__</code> if the name
- * +send+ clashes with an existing method in _obj_.
- *
- * class Klass
- * def hello(*args)
- * "Hello " + args.join(' ')
- * end
- * end
- * k = Klass.new
- * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
- */
-static mrb_value
-mrb_f_send(mrb_state *mrb, mrb_value self)
-{
- mrb_sym name;
- mrb_value block, *argv;
- int argc;
-
- mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
- return mrb_funcall_with_block(mrb,self, name, argc, argv, block);
-}
-
/* 15.3.1.2.2 */
/* 15.3.1.2.5 */
/* 15.3.1.3.6 */
@@ -218,7 +188,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
mrb_value *bp;
mrb_bool given_p;
- bp = mrb->c->stbase + ci->stackidx + 1;
+ bp = ci->stackent + 1;
ci--;
if (ci <= mrb->c->cibase) {
given_p = 0;
@@ -240,6 +210,26 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
return mrb_bool_value(given_p);
}
+/*
+ * call-seq:
+ * __method__ -> symbol
+ *
+ * Returns the name at the definition of the current method as a
+ * Symbol.
+ * If called outside of a method, it returns <code>nil</code>.
+ *
+ */
+static mrb_value
+mrb_f_method(mrb_state *mrb, mrb_value self)
+{
+ mrb_callinfo *ci = mrb->c->ci;
+ ci--;
+ if (ci->mid)
+ return mrb_symbol_value(ci->mid);
+ else
+ return mrb_nil_value();
+}
+
/* 15.3.1.3.7 */
/*
* call-seq:
@@ -280,7 +270,7 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
clone->super = klass->super;
if (klass->iv) {
mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
- mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern2(mrb, "__attached__", 12), obj);
+ mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern_lit(mrb, "__attached__"), obj);
}
if (klass->mt) {
clone->mt = kh_copy(mt, mrb, klass->mt);
@@ -294,12 +284,23 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
}
static void
+copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
+{
+ struct RClass *dc = mrb_class_ptr(dst);
+ struct RClass *sc = mrb_class_ptr(src);
+ dc->mt = kh_copy(mt, mrb, sc->mt);
+ dc->super = sc->super;
+}
+
+static void
init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
{
- switch (mrb_type(obj)) {
- case MRB_TT_OBJECT:
+ switch (mrb_type(obj)) {
case MRB_TT_CLASS:
case MRB_TT_MODULE:
+ copy_class(mrb, dest, obj);
+ /* fall through */
+ case MRB_TT_OBJECT:
case MRB_TT_SCLASS:
case MRB_TT_HASH:
case MRB_TT_DATA:
@@ -474,8 +475,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c);
-
/* 15.3.1.3.18 */
/*
* call-seq:
@@ -518,7 +517,7 @@ mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
c = mrb_class_ptr(cv);
break;
}
- return mrb_yield_internal(mrb, b, 0, 0, self, c);
+ return mrb_yield_with_class(mrb, b, 0, 0, self, c);
}
mrb_bool
@@ -542,14 +541,14 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self)
mrb_value arg;
mrb_bool instance_of_p;
- mrb_get_args(mrb, "o", &arg);
+ mrb_get_args(mrb, "C", &arg);
instance_of_p = mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg));
return mrb_bool_value(instance_of_p);
}
static void
-valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, size_t len)
+valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, mrb_int len)
{
if (len < 2 || !(s[0] == '@' && s[1] != '@')) {
mrb_name_error(mrb, iv_name_id, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name_id));
@@ -560,7 +559,7 @@ static void
check_iv_name(mrb_state *mrb, mrb_sym iv_name_id)
{
const char *s;
- size_t len;
+ mrb_int len;
s = mrb_sym2name_len(mrb, iv_name_id, &len);
valid_iv_name(mrb, iv_name_id, s, len);
@@ -574,8 +573,10 @@ get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name)
mrb_assert(mrb_symbol_p(iv_name) || mrb_string_p(iv_name));
if (mrb_string_p(iv_name)) {
- iv_name_id = mrb_intern_cstr(mrb, RSTRING_PTR(iv_name));
- valid_iv_name(mrb, iv_name_id, RSTRING_PTR(iv_name), RSTRING_LEN(iv_name));
+ char *p = RSTRING_PTR(iv_name);
+ mrb_int l = RSTRING_LEN(iv_name);
+ iv_name_id = mrb_intern(mrb, p, l);
+ valid_iv_name(mrb, iv_name_id, p, l);
}
else {
iv_name_id = mrb_symbol(iv_name);
@@ -715,14 +716,17 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
mrb_value arg;
mrb_bool kind_of_p;
- mrb_get_args(mrb, "o", &arg);
+ mrb_get_args(mrb, "C", &arg);
kind_of_p = mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg));
return mrb_bool_value(kind_of_p);
}
+KHASH_DECLARE(st, mrb_sym, char, FALSE)
+KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal)
+
static void
-method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
+method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
{
khint_t i;
@@ -730,21 +734,22 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
if (!h) return;
for (i=0;i<kh_end(h);i++) {
if (kh_exist(h, i)) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(h,i)));
+ kh_put(st, mrb, set, kh_key(h,i));
}
}
}
mrb_value
-class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
+mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* oldklass;
+ khash_t(st)* set = kh_init(st, mrb);
- ary = mrb_ary_new(mrb);
oldklass = 0;
while (klass && (klass != oldklass)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
if ((klass->tt == MRB_TT_ICLASS) ||
(klass->tt == MRB_TT_SCLASS)) {
}
@@ -755,28 +760,46 @@ class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass,
klass = klass->super;
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, mrb, set);
+
return ary;
}
mrb_value
mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* klass;
+ khash_t(st)* set = kh_init(st, mrb);
klass = mrb_class(mrb, obj);
- ary = mrb_ary_new(mrb);
+
if (klass && (klass->tt == MRB_TT_SCLASS)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
if (recur) {
while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, mrb, set);
+
return ary;
}
@@ -784,7 +807,7 @@ mrb_value
mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag)
{
if (recur)
- return class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
+ return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
else
return mrb_obj_singleton_methods(mrb, recur, obj);
}
@@ -922,7 +945,7 @@ mrb_f_raise(mrb_state *mrb, mrb_value self)
/* fall through */
default:
exc = mrb_make_exception(mrb, argc, a);
- mrb_obj_iv_set(mrb, mrb_obj_ptr(exc), mrb_intern2(mrb, "lastpc", 6), mrb_voidp_value(mrb, mrb->c->ci->pc));
+ mrb_obj_iv_set(mrb, mrb_obj_ptr(exc), mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, mrb->c->ci->pc));
mrb_exc_raise(mrb, exc);
break;
}
@@ -987,7 +1010,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub)
* If the method is not defined, <code>respond_to_missing?</code>
* method is called and the result is returned.
*/
-mrb_value
+static mrb_value
obj_respond_to(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
@@ -1027,7 +1050,7 @@ obj_respond_to(mrb_state *mrb, mrb_value self)
}
if (!respond_to_p) {
- rtm_id = mrb_intern2(mrb, "respond_to_missing?", 19);
+ rtm_id = mrb_intern_lit(mrb, "respond_to_missing?");
if (basic_obj_respond_to(mrb, self, rtm_id, !mrb_test(priv))) {
return mrb_funcall_argv(mrb, self, rtm_id, argc, argv);
}
@@ -1076,6 +1099,41 @@ mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self)
return mrb_obj_singleton_methods(mrb, recur, self);
}
+static mrb_value
+mod_define_singleton_method(mrb_state *mrb, mrb_value self)
+{
+ struct RProc *p;
+ mrb_sym mid;
+ mrb_value blk = mrb_nil_value();
+
+ mrb_get_args(mrb, "n&", &mid, &blk);
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+ mrb_proc_copy(p, mrb_proc_ptr(blk));
+ p->flags |= MRB_PROC_STRICT;
+ mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, p);
+ return mrb_symbol_value(mid);
+}
+
+static mrb_value
+mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
+{
+ mrb_value v;
+ mrb_int i, len;
+ mrb_sym eqq = mrb_intern_lit(mrb, "===");
+ mrb_value ary = mrb_ary_splat(mrb, self);
+
+ mrb_get_args(mrb, "o", &v);
+ len = RARRAY_LEN(ary);
+ for (i=0; i<len; i++) {
+ mrb_value c = mrb_funcall_argv(mrb, mrb_ary_entry(ary, i), eqq, 1, &v);
+ if (mrb_test(c)) return mrb_true_value();
+ }
+ return mrb_false_value();
+}
+
void
mrb_init_kernel(mrb_state *mrb)
{
@@ -1095,6 +1153,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */
mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
+ mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */
mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */
mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */
@@ -1126,8 +1185,10 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */
mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */
mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */
+ mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY());
mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */
+ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */
mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
- mrb_alias_method(mrb, mrb->module_class, mrb_intern2(mrb, "dup", 3), mrb_intern2(mrb, "clone", 5));
+ mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone"));
}
diff --git a/src/load.c b/src/load.c
index 092ddbde8..d97776a16 100644
--- a/src/load.c
+++ b/src/load.c
@@ -4,18 +4,15 @@
** See Copyright Notice in mruby.h
*/
-#ifndef SIZE_MAX
- /* Some versions of VC++
- * has SIZE_MAX in stdint.h
- */
-# include <limits.h>
-#endif
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "mruby/dump.h"
#include "mruby/irep.h"
#include "mruby/proc.h"
#include "mruby/string.h"
+#include "mruby/debug.h"
+#include "mruby/error.h"
#if !defined(_WIN32) && SIZE_MAX < UINT32_MAX
# define SIZE_ERROR_MUL(x, y) ((x) > SIZE_MAX / (y))
@@ -29,30 +26,9 @@
# error This code assumes CHAR_BIT == 8
#endif
-static void
-irep_free(size_t sirep, mrb_state *mrb)
-{
- size_t i;
- void *p;
-
- for (i = sirep; i < mrb->irep_len; i++) {
- if (mrb->irep[i]) {
- p = mrb->irep[i]->iseq;
- if (p)
- mrb_free(mrb, p);
-
- p = mrb->irep[i]->pool;
- if (p)
- mrb_free(mrb, p);
-
- p = mrb->irep[i]->syms;
- if (p)
- mrb_free(mrb, p);
-
- mrb_free(mrb, mrb->irep[i]);
- }
- }
-}
+#if UINT32_MAX > SIZE_MAX
+# error This code cannot be built on your environment.
+#endif
static size_t
offset_crc_body(void)
@@ -61,83 +37,84 @@ offset_crc_body(void)
return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc);
}
-static int
-read_rite_irep_record(mrb_state *mrb, const uint8_t *bin, uint32_t *len)
+static mrb_irep*
+read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
{
- int ret;
size_t i;
const uint8_t *src = bin;
+ ptrdiff_t diff;
uint16_t tt, pool_data_len, snl;
size_t plen;
int ai = mrb_gc_arena_save(mrb);
mrb_irep *irep = mrb_add_irep(mrb);
- // skip record size
+ /* skip record size */
src += sizeof(uint32_t);
- // number of local variable
+ /* number of local variable */
irep->nlocals = bin_to_uint16(src);
src += sizeof(uint16_t);
- // number of register variable
+ /* number of register variable */
irep->nregs = bin_to_uint16(src);
src += sizeof(uint16_t);
- // Binary Data Section
- // ISEQ BLOCK
- irep->ilen = bin_to_uint32(src);
+ /* number of child irep */
+ irep->rlen = (size_t)bin_to_uint16(src);
+ src += sizeof(uint16_t);
+
+ /* Binary Data Section */
+ /* ISEQ BLOCK */
+ irep->ilen = (size_t)bin_to_uint32(src);
src += sizeof(uint32_t);
if (irep->ilen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
+ return NULL;
}
irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen);
- if (irep->iseq == NULL) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
for (i = 0; i < irep->ilen; i++) {
- irep->iseq[i] = bin_to_uint32(src); //iseq
+ irep->iseq[i] = (size_t)bin_to_uint32(src); /* iseq */
src += sizeof(uint32_t);
}
}
- //POOL BLOCK
- plen = bin_to_uint32(src); /* number of pool */
+ /* POOL BLOCK */
+ plen = (size_t)bin_to_uint32(src); /* number of pool */
src += sizeof(uint32_t);
if (plen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_value), plen)) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
- irep->pool = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value) * plen);
- if (irep->pool == NULL) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
+ return NULL;
}
+ irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen);
for (i = 0; i < plen; i++) {
mrb_value s;
- tt = *src++; //pool TT
- pool_data_len = bin_to_uint16(src); //pool data length
+
+ tt = *src++; /* pool TT */
+ pool_data_len = bin_to_uint16(src); /* pool data length */
src += sizeof(uint16_t);
- s = mrb_str_new(mrb, (char *)src, pool_data_len);
+ if (alloc) {
+ s = mrb_str_new(mrb, (char *)src, pool_data_len);
+ }
+ else {
+ s = mrb_str_new_static(mrb, (char *)src, pool_data_len);
+ }
src += pool_data_len;
- switch (tt) { //pool data
- case MRB_TT_FIXNUM:
+ switch (tt) { /* pool data */
+ case IREP_TT_FIXNUM:
irep->pool[i] = mrb_str_to_inum(mrb, s, 10, FALSE);
break;
- case MRB_TT_FLOAT:
- irep->pool[i] = mrb_float_value(mrb, mrb_str_to_dbl(mrb, s, FALSE));
+ case IREP_TT_FLOAT:
+ irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE));
break;
- case MRB_TT_STRING:
- irep->pool[i] = s;
+ case IREP_TT_STRING:
+ irep->pool[i] = mrb_str_pool(mrb, s);
break;
default:
+ /* should not happen */
irep->pool[i] = mrb_nil_value();
break;
}
@@ -146,22 +123,17 @@ read_rite_irep_record(mrb_state *mrb, const uint8_t *bin, uint32_t *len)
}
}
- //SYMS BLOCK
- irep->slen = bin_to_uint32(src); //syms length
+ /* SYMS BLOCK */
+ irep->slen = (size_t)bin_to_uint32(src); /* syms length */
src += sizeof(uint32_t);
if (irep->slen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_sym), irep->slen)) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
+ return NULL;
}
irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
- if (irep->syms == NULL) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
for (i = 0; i < irep->slen; i++) {
- snl = bin_to_uint16(src); //symbol name length
+ snl = bin_to_uint16(src); /* symbol name length */
src += sizeof(uint16_t);
if (snl == MRB_DUMP_NULL_SYM_LEN) {
@@ -169,53 +141,56 @@ read_rite_irep_record(mrb_state *mrb, const uint8_t *bin, uint32_t *len)
continue;
}
- irep->syms[i] = mrb_intern2(mrb, (char *)src, snl);
+ if (alloc) {
+ irep->syms[i] = mrb_intern(mrb, (char *)src, snl);
+ }
+ else {
+ irep->syms[i] = mrb_intern_static(mrb, (char *)src, snl);
+ }
src += snl + 1;
mrb_gc_arena_restore(mrb, ai);
}
}
- *len = src - bin;
- ret = MRB_DUMP_OK;
-error_exit:
- return ret;
+ irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*irep->rlen);
+
+ diff = src - bin;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= SIZE_MAX);
+ *len = (size_t)diff;
+
+ return irep;
}
-static int
-read_rite_section_irep(mrb_state *mrb, const uint8_t *bin)
+static mrb_irep*
+read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
{
- int result;
- size_t sirep;
- uint32_t len;
- uint16_t nirep;
- uint16_t n;
- const struct rite_section_irep_header *header;
-
- header = (const struct rite_section_irep_header*)bin;
- bin += sizeof(struct rite_section_irep_header);
+ mrb_irep *irep = read_irep_record_1(mrb, bin, len, alloc);
+ size_t i;
- sirep = mrb->irep_len;
- nirep = bin_to_uint16(header->nirep);
+ bin += *len;
+ for (i=0; i<irep->rlen; i++) {
+ size_t rlen;
- //Read Binary Data Section
- for (n = 0; n < nirep; n++) {
- result = read_rite_irep_record(mrb, bin, &len);
- if (result != MRB_DUMP_OK)
- goto error_exit;
- bin += len;
+ irep->reps[i] = read_irep_record(mrb, bin, &rlen, alloc);
+ bin += rlen;
+ *len += rlen;
}
+ return irep;
+}
- result = nirep;
-error_exit:
- if (result < MRB_DUMP_OK) {
- irep_free(sirep, mrb);
- }
- return result;
+static mrb_irep*
+read_section_irep(mrb_state *mrb, const uint8_t *bin, mrb_bool alloc)
+{
+ size_t len;
+
+ bin += sizeof(struct rite_section_irep_header);
+ return read_irep_record(mrb, bin, &len, alloc);
}
static int
-read_rite_lineno_record(mrb_state *mrb, const uint8_t *bin, size_t irepno, uint32_t *len)
+read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len)
{
int ret;
size_t i, fname_len, niseq;
@@ -224,84 +199,214 @@ read_rite_lineno_record(mrb_state *mrb, const uint8_t *bin, size_t irepno, uint3
ret = MRB_DUMP_OK;
*len = 0;
- bin += sizeof(uint32_t); // record size
+ bin += sizeof(uint32_t); /* record size */
*len += sizeof(uint32_t);
fname_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
*len += sizeof(uint16_t);
if (SIZE_ERROR(fname_len + 1)) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
+ return MRB_DUMP_GENERAL_FAILURE;
}
fname = (char *)mrb_malloc(mrb, fname_len + 1);
- if (fname == NULL) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
memcpy(fname, bin, fname_len);
fname[fname_len] = '\0';
bin += fname_len;
*len += fname_len;
- niseq = bin_to_uint32(bin);
- bin += sizeof(uint32_t); // niseq
+ niseq = (size_t)bin_to_uint32(bin);
+ bin += sizeof(uint32_t); /* niseq */
*len += sizeof(uint32_t);
if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
+ return MRB_DUMP_GENERAL_FAILURE;
}
lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t));
- if (lines == NULL) {
- ret = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
for (i = 0; i < niseq; i++) {
lines[i] = bin_to_uint16(bin);
- bin += sizeof(uint16_t); // niseq
+ bin += sizeof(uint16_t); /* niseq */
*len += sizeof(uint16_t);
- }
-
- mrb->irep[irepno]->filename = fname;
- mrb->irep[irepno]->lines = lines;
-
-error_exit:
+ }
+ irep->filename = fname;
+ irep->lines = lines;
return ret;
}
static int
-read_rite_section_lineno(mrb_state *mrb, const uint8_t *bin, size_t sirep)
+read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp)
{
- int result;
+ int result = read_lineno_record_1(mrb, bin, irep, lenp);
size_t i;
- uint32_t len;
- uint16_t nirep;
- uint16_t n;
- const struct rite_section_lineno_header *header;
+
+ if (result != MRB_DUMP_OK) return result;
+ for (i = 0; i < irep->rlen; i++) {
+ size_t len;
+
+ result = read_lineno_record(mrb, bin, irep->reps[i], &len);
+ if (result != MRB_DUMP_OK) break;
+ bin += len;
+ *lenp += len;
+ }
+ return result;
+}
+
+static int
+read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep)
+{
+ size_t len;
len = 0;
- header = (const struct rite_section_lineno_header*)bin;
bin += sizeof(struct rite_section_lineno_header);
- nirep = bin_to_uint16(header->nirep);
+ /* Read Binary Data Section */
+ return read_lineno_record(mrb, bin, irep, &len);
+}
- //Read Binary Data Section
- for (n = 0, i = sirep; n < nirep; n++, i++) {
- result = read_rite_lineno_record(mrb, bin, i, &len);
- if (result != MRB_DUMP_OK)
- goto error_exit;
+static int
+read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
+{
+ const uint8_t *bin = start;
+ ptrdiff_t diff;
+ size_t record_size, i;
+ uint16_t f_idx;
+
+ if (irep->debug_info) { return MRB_DUMP_INVALID_IREP; }
+
+ irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
+ irep->debug_info->pc_count = irep->ilen;
+
+ record_size = (size_t)bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+
+ irep->debug_info->flen = bin_to_uint16(bin);
+ irep->debug_info->files = (mrb_irep_debug_info_file**)mrb_malloc(mrb, sizeof(mrb_irep_debug_info*) * irep->debug_info->flen);
+ bin += sizeof(uint16_t);
+
+ for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file *file;
+ uint16_t filename_idx;
+ mrb_int len;
+
+ file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file));
+ irep->debug_info->files[f_idx] = file;
+
+ file->start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+
+ /* filename */
+ filename_idx = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ mrb_assert(filename_idx < filenames_len);
+ file->filename_sym = filenames[filename_idx];
+ len = 0;
+ file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len);
+
+ file->line_entry_count = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ file->line_type = (mrb_debug_line_type)bin_to_uint8(bin);
+ bin += sizeof(uint8_t);
+ switch (file->line_type) {
+ case mrb_debug_line_ary: {
+ uint32_t l;
+
+ file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count));
+ for (l = 0; l < file->line_entry_count; ++l) {
+ file->lines.ary[l] = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ }
+ } break;
+
+ case mrb_debug_line_flat_map: {
+ uint32_t l;
+
+ file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(
+ mrb, sizeof(mrb_irep_debug_info_line) * (size_t)(file->line_entry_count));
+ for (l = 0; l < file->line_entry_count; ++l) {
+ file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
+ bin += sizeof(uint32_t);
+ file->lines.flat_map[l].line = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ }
+ } break;
+
+ default: return MRB_DUMP_GENERAL_FAILURE;
+ }
+ }
+
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= SIZE_MAX);
+
+ if (record_size != (size_t)diff) {
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < irep->rlen; i++) {
+ size_t len;
+ int ret;
+
+ ret =read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
+ if (ret != MRB_DUMP_OK) return ret;
bin += len;
}
- result = sirep + bin_to_uint16(header->sirep);
-error_exit:
- return result;
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= SIZE_MAX);
+ *record_len = (size_t)diff;
+
+ return MRB_DUMP_OK;
}
+static int
+read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc)
+{
+ const uint8_t *bin;
+ ptrdiff_t diff;
+ struct rite_section_debug_header *header;
+ uint16_t i;
+ size_t len = 0;
+ int result;
+ uint16_t filenames_len;
+ mrb_sym *filenames;
+
+ bin = start;
+ header = (struct rite_section_debug_header *)bin;
+ bin += sizeof(struct rite_section_debug_header);
+
+ filenames_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len);
+ for (i = 0; i < filenames_len; ++i) {
+ uint16_t f_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ if (alloc) {
+ filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
+ }
+ else {
+ filenames[i] = mrb_intern_static(mrb, (const char *)bin, (size_t)f_len);
+ }
+ bin += f_len;
+ }
+
+ result = read_debug_record(mrb, bin, irep, &len, filenames, filenames_len);
+ if (result != MRB_DUMP_OK) goto debug_exit;
+
+ bin += len;
+ diff = bin - start;
+ mrb_assert(diff >= 0);
+ mrb_assert(diff <= UINT32_MAX);
+ if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
+ result = MRB_DUMP_GENERAL_FAILURE;
+ }
+
+debug_exit:
+ mrb_free(mrb, filenames);
+ return result;
+}
static int
-read_rite_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
+read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
{
const struct rite_binary_header *header = (const struct rite_binary_header *)bin;
@@ -315,226 +420,196 @@ read_rite_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
*crc = bin_to_uint16(header->binary_crc);
if (bin_size) {
- *bin_size = bin_to_uint32(header->binary_size);
+ *bin_size = (size_t)bin_to_uint32(header->binary_size);
}
return MRB_DUMP_OK;
}
-int32_t
+mrb_irep*
mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
{
int result;
- int32_t total_nirep = 0;
+ mrb_irep *irep = NULL;
const struct rite_section_header *section_header;
uint16_t crc;
size_t bin_size = 0;
size_t n;
- size_t sirep;
if ((mrb == NULL) || (bin == NULL)) {
- return MRB_DUMP_INVALID_ARGUMENT;
+ return NULL;
}
- result = read_rite_binary_header(bin, &bin_size, &crc);
+ result = read_binary_header(bin, &bin_size, &crc);
if (result != MRB_DUMP_OK) {
- return result;
+ return NULL;
}
n = offset_crc_body();
if (crc != calc_crc_16_ccitt(bin + n, bin_size - n, 0)) {
- return MRB_DUMP_INVALID_FILE_HEADER;
+ return NULL;
}
bin += sizeof(struct rite_binary_header);
- sirep = mrb->irep_len;
-
do {
section_header = (const struct rite_section_header *)bin;
if (memcmp(section_header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
- result = read_rite_section_irep(mrb, bin);
+ irep = read_section_irep(mrb, bin, FALSE);
+ if (!irep) return NULL;
+ }
+ else if (memcmp(section_header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ if (!irep) return NULL; /* corrupted data */
+ result = read_section_lineno(mrb, bin, irep);
if (result < MRB_DUMP_OK) {
- return result;
+ return NULL;
}
- total_nirep += result;
}
- else if (memcmp(section_header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
- result = read_rite_section_lineno(mrb, bin, sirep);
+ else if (memcmp(section_header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ if (!irep) return NULL; /* corrupted data */
+ result = read_section_debug(mrb, bin, irep, FALSE);
if (result < MRB_DUMP_OK) {
- return result;
+ return NULL;
}
}
bin += bin_to_uint32(section_header->section_size);
} while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0);
- return sirep;
+ return irep;
}
static void
-irep_error(mrb_state *mrb, int n)
+irep_error(mrb_state *mrb)
{
- static const char msg[] = "irep load error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SCRIPT_ERROR, msg, sizeof(msg) - 1));
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
mrb_value
-mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
+mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
{
- int32_t n;
+ mrb_irep *irep = mrb_read_irep(mrb, bin);
+ mrb_value val;
+ struct RProc *proc;
- n = mrb_read_irep(mrb, bin);
- if (n < 0) {
- irep_error(mrb, n);
+ if (!irep) {
+ irep_error(mrb);
return mrb_nil_value();
}
- return mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));
+ proc = mrb_proc_new(mrb, irep);
+ mrb_irep_decref(mrb, irep);
+ if (c && c->no_exec) return mrb_obj_value(proc);
+ val = mrb_toplevel_run(mrb, proc);
+ return val;
+}
+
+mrb_value
+mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
+{
+ return mrb_load_irep_cxt(mrb, bin, NULL);
}
#ifdef ENABLE_STDIO
-static int32_t
-read_rite_section_lineno_file(mrb_state *mrb, FILE *fp, size_t sirep)
+static int
+read_lineno_record_file(mrb_state *mrb, FILE *fp, mrb_irep *irep)
{
- int32_t result;
- size_t i;
- uint16_t nirep;
- uint16_t n;
- uint32_t len, buf_size;
- uint8_t *buf = NULL;
- const size_t record_header_size = 4;
+ uint8_t header[4];
+ const size_t record_header_size = sizeof(header);
+ int result;
+ size_t i, buf_size;
+ size_t len;
+ void *ptr;
+ uint8_t *buf;
- struct rite_section_lineno_header header;
- if (fread(&header, sizeof(struct rite_section_lineno_header), 1, fp) == 0) {
+ if (fread(header, record_header_size, 1, fp) == 0) {
return MRB_DUMP_READ_FAULT;
}
-
- nirep = bin_to_uint16(header.nirep);
-
- buf_size = record_header_size;
- /* We don't need to check buf_size. As it is enough small. */
- buf = (uint8_t *)mrb_malloc(mrb, buf_size);
- if (!buf) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
-
- //Read Binary Data Section
- for (n = 0, i = sirep; n < nirep; n++, i++) {
- void *ptr;
-
- if (fread(buf, record_header_size, 1, fp) == 0) {
- result = MRB_DUMP_READ_FAULT;
- goto error_exit;
- }
- buf_size = bin_to_uint32(&buf[0]);
- if (SIZE_ERROR(buf_size)) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
- ptr = mrb_realloc(mrb, buf, buf_size);
- if (!ptr) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
- buf = (uint8_t *)ptr;
-
- if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
- result = MRB_DUMP_READ_FAULT;
- goto error_exit;
- }
- result = read_rite_lineno_record(mrb, buf, i, &len);
- if (result != MRB_DUMP_OK)
- goto error_exit;
+ buf_size = (size_t)bin_to_uint32(&header[0]);
+ if (SIZE_ERROR(buf_size)) {
+ return MRB_DUMP_GENERAL_FAILURE;
}
+ ptr = mrb_malloc(mrb, buf_size);
+ buf = (uint8_t *)ptr;
- result = sirep + bin_to_uint16(header.sirep);
-error_exit:
- if (buf) {
- mrb_free(mrb, buf);
+ if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
+ return MRB_DUMP_READ_FAULT;
}
- if (result < MRB_DUMP_OK) {
- irep_free(sirep, mrb);
+ result = read_lineno_record_1(mrb, buf, irep, &len);
+ mrb_free(mrb, ptr);
+ if (result != MRB_DUMP_OK) return result;
+ for (i = 0; i < irep->rlen; i++) {
+ result = read_lineno_record_file(mrb, fp, irep->reps[i]);
+ if (result != MRB_DUMP_OK) break;
}
return result;
}
static int32_t
-read_rite_section_irep_file(mrb_state *mrb, FILE *fp)
+read_section_lineno_file(mrb_state *mrb, FILE *fp, mrb_irep *irep)
{
- int32_t result;
- size_t sirep;
- uint16_t nirep;
- uint16_t n;
- uint32_t len, buf_size;
- uint8_t *buf = NULL;
- const size_t record_header_size = 1 + 4;
- struct rite_section_irep_header header;
+ struct rite_section_lineno_header header;
- if (fread(&header, sizeof(struct rite_section_irep_header), 1, fp) == 0) {
+ if (fread(&header, sizeof(struct rite_section_lineno_header), 1, fp) == 0) {
return MRB_DUMP_READ_FAULT;
}
- sirep = mrb->irep_len;
- nirep = bin_to_uint16(header.nirep);
-
- buf_size = record_header_size;
- /* You don't need use SIZE_ERROR as buf_size is enough small. */
- buf = (uint8_t *)mrb_malloc(mrb, buf_size);
- if (!buf) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
-
- //Read Binary Data Section
- for (n = 0; n < nirep; n++) {
- void *ptr;
+ /* Read Binary Data Section */
+ return read_lineno_record_file(mrb, fp, irep);
+}
- if (fread(buf, record_header_size, 1, fp) == 0) {
- result = MRB_DUMP_READ_FAULT;
- goto error_exit;
- }
- buf_size = bin_to_uint32(&buf[0]);
- if (SIZE_ERROR(buf_size)) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
- ptr = mrb_realloc(mrb, buf, buf_size);
- if (!ptr) {
- result = MRB_DUMP_GENERAL_FAILURE;
- goto error_exit;
- }
- buf = (uint8_t *)ptr;
+static mrb_irep*
+read_irep_record_file(mrb_state *mrb, FILE *fp)
+{
+ uint8_t header[1 + 4];
+ const size_t record_header_size = sizeof(header);
+ size_t buf_size, i;
+ size_t len;
+ mrb_irep *irep = NULL;
+ void *ptr;
+ uint8_t *buf;
- if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
- result = MRB_DUMP_READ_FAULT;
- goto error_exit;
- }
- result = read_rite_irep_record(mrb, buf, &len);
- if (result != MRB_DUMP_OK)
- goto error_exit;
+ if (fread(header, record_header_size, 1, fp) == 0) {
+ return NULL;
}
-
- result = nirep;
-error_exit:
- if (buf) {
- mrb_free(mrb, buf);
+ buf_size = (size_t)bin_to_uint32(&header[0]);
+ if (SIZE_ERROR(buf_size)) {
+ return NULL;
}
- if (result < MRB_DUMP_OK) {
- irep_free(sirep, mrb);
+ ptr = mrb_malloc(mrb, buf_size);
+ buf = (uint8_t *)ptr;
+ memcpy(buf, header, record_header_size);
+ if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
+ return NULL;
}
- return result;
+ irep = read_irep_record_1(mrb, buf, &len, TRUE);
+ mrb_free(mrb, ptr);
+ if (!irep) return NULL;
+ for (i=0; i<irep->rlen; i++) {
+ irep->reps[i] = read_irep_record_file(mrb, fp);
+ if (!irep->reps[i]) return NULL;
+ }
+ return irep;
+}
+
+static mrb_irep*
+read_section_irep_file(mrb_state *mrb, FILE *fp)
+{
+ struct rite_section_irep_header header;
+
+ if (fread(&header, sizeof(struct rite_section_irep_header), 1, fp) == 0) {
+ return NULL;
+ }
+ return read_irep_record_file(mrb, fp);
}
-int32_t
+mrb_irep*
mrb_read_irep_file(mrb_state *mrb, FILE* fp)
{
+ mrb_irep *irep = NULL;
int result;
- int32_t total_nirep = 0;
uint8_t *buf;
uint16_t crc, crcwk = 0;
- uint32_t section_size = 0;
+ size_t section_size = 0;
size_t nbytes;
- size_t sirep;
struct rite_section_header section_header;
long fpos;
size_t block_size = 1 << 14;
@@ -543,33 +618,30 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
const size_t buf_size = sizeof(struct rite_binary_header);
if ((mrb == NULL) || (fp == NULL)) {
- return MRB_DUMP_INVALID_ARGUMENT;
+ return NULL;
}
/* You don't need use SIZE_ERROR as buf_size is enough small. */
- buf = mrb_malloc(mrb, buf_size);
- if (!buf) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
+ buf = (uint8_t*)mrb_malloc(mrb, buf_size);
if (fread(buf, buf_size, 1, fp) == 0) {
mrb_free(mrb, buf);
- return MRB_DUMP_READ_FAULT;
+ return NULL;
}
- result = read_rite_binary_header(buf, NULL, &crc);
+ result = read_binary_header(buf, NULL, &crc);
mrb_free(mrb, buf);
if (result != MRB_DUMP_OK) {
- return result;
+ return NULL;
}
/* verify CRC */
fpos = ftell(fp);
/* You don't need use SIZE_ERROR as block_size is enough small. */
for (i = 0; i < block_fallback_count; i++,block_size >>= 1){
- buf = mrb_malloc_simple(mrb, block_size);
- if (buf) break;
+ buf = (uint8_t*)mrb_malloc_simple(mrb, block_size);
+ if (buf) break;
}
if (!buf) {
- return MRB_DUMP_GENERAL_FAILURE;
+ return NULL;
}
fseek(fp, offset_crc_body(), SEEK_SET);
while ((nbytes = fread(buf, 1, block_size, fp)) > 0) {
@@ -577,53 +649,75 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
}
mrb_free(mrb, buf);
if (nbytes == 0 && ferror(fp)) {
- return MRB_DUMP_READ_FAULT;
+ return NULL;
}
if (crcwk != crc) {
- return MRB_DUMP_INVALID_FILE_HEADER;
+ return NULL;
}
fseek(fp, fpos + section_size, SEEK_SET);
- sirep = mrb->irep_len;
- // read sections
+ /* read sections */
do {
fpos = ftell(fp);
if (fread(&section_header, sizeof(struct rite_section_header), 1, fp) == 0) {
- return MRB_DUMP_READ_FAULT;
+ return NULL;
}
- section_size = bin_to_uint32(section_header.section_size);
+ section_size = (size_t)bin_to_uint32(section_header.section_size);
if (memcmp(section_header.section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
fseek(fp, fpos, SEEK_SET);
- result = read_rite_section_irep_file(mrb, fp);
- if (result < MRB_DUMP_OK) {
- return result;
- }
- total_nirep += result;
+ irep = read_section_irep_file(mrb, fp);
+ if (!irep) return NULL;
}
else if (memcmp(section_header.section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
+ if (!irep) return NULL; /* corrupted data */
fseek(fp, fpos, SEEK_SET);
- result = read_rite_section_lineno_file(mrb, fp, sirep);
- if (result < MRB_DUMP_OK) {
- return result;
+ result = read_section_lineno_file(mrb, fp, irep);
+ if (result < MRB_DUMP_OK) return NULL;
+ }
+ else if (memcmp(section_header.section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
+ if (!irep) return NULL; /* corrupted data */
+ else {
+ uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size);
+
+ fseek(fp, fpos, SEEK_SET);
+ if (fread((char*)bin, section_size, 1, fp) != 1) {
+ mrb_free(mrb, bin);
+ return NULL;
+ }
+ result = read_section_debug(mrb, bin, irep, TRUE);
+ mrb_free(mrb, bin);
}
+ if (result < MRB_DUMP_OK) return NULL;
}
fseek(fp, fpos + section_size, SEEK_SET);
} while (memcmp(section_header.section_identify, RITE_BINARY_EOF, sizeof(section_header.section_identify)) != 0);
- return sirep;
+ return irep;
}
mrb_value
-mrb_load_irep_file(mrb_state *mrb, FILE* fp)
+mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
{
- int n = mrb_read_irep_file(mrb, fp);
+ mrb_irep *irep = mrb_read_irep_file(mrb, fp);
+ mrb_value val;
+ struct RProc *proc;
- if (n < 0) {
- irep_error(mrb, n);
+ if (!irep) {
+ irep_error(mrb);
return mrb_nil_value();
}
- return mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));
+ proc = mrb_proc_new(mrb, irep);
+ mrb_irep_decref(mrb, irep);
+ if (c && c->no_exec) return mrb_obj_value(proc);
+ val = mrb_toplevel_run(mrb, proc);
+ return val;
+}
+
+mrb_value
+mrb_load_irep_file(mrb_state *mrb, FILE* fp)
+{
+ return mrb_load_irep_file_cxt(mrb, fp, NULL);
}
#endif /* ENABLE_STDIO */
diff --git a/src/mrb_throw.h b/src/mrb_throw.h
new file mode 100644
index 000000000..3c7407a8d
--- /dev/null
+++ b/src/mrb_throw.h
@@ -0,0 +1,41 @@
+/*
+** mrb_throw.h - mruby exception throwing handler
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRB_THROW_H
+#define MRB_THROW_H
+
+#ifdef MRB_ENABLE_CXX_EXCEPTION
+
+#define MRB_TRY(buf) do { try {
+#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; }
+#define MRB_END_EXC(buf) } } while(0)
+
+#define MRB_THROW(buf) throw((buf)->impl)
+typedef mrb_int mrb_jmpbuf_impl;
+
+#else
+
+#include <setjmp.h>
+
+#define MRB_TRY(buf) do { if (setjmp((buf)->impl) == 0) {
+#define MRB_CATCH(buf) } else {
+#define MRB_END_EXC(buf) } } while(0)
+
+#define MRB_THROW(buf) longjmp((buf)->impl, 1);
+#define mrb_jmpbuf_impl jmp_buf
+
+#endif
+
+struct mrb_jmpbuf {
+ mrb_jmpbuf_impl impl;
+
+#ifdef MRB_ENABLE_CXX_EXCEPTION
+ static mrb_int jmpbuf_id;
+ mrb_jmpbuf() : impl(jmpbuf_id++) {}
+#endif
+};
+
+#endif /* MRB_THROW_H */
diff --git a/src/mruby_core.rake b/src/mruby_core.rake
index db335223d..87759aa61 100644
--- a/src/mruby_core.rake
+++ b/src/mruby_core.rake
@@ -4,8 +4,62 @@ MRuby.each_target do
current_build_dir = "#{build_dir}/#{relative_from_root}"
lex_def = "#{current_dir}/lex.def"
- objs = Dir.glob("#{current_dir}/*.c").map { |f| objfile(f.pathmap("#{current_build_dir}/%n")) }
- objs += [objfile("#{current_build_dir}/y.tab")]
+ objs = Dir.glob("#{current_dir}/*.c").map { |f|
+ next nil if cxx_abi_enabled? and f =~ /(codegen|error|vm).c$/
+ objfile(f.pathmap("#{current_build_dir}/%n"))
+ }.compact
+
+ if cxx_abi_enabled?
+ cxx_abi_dependency = %w(codegen error vm)
+ cxx_abi_objs = cxx_abi_dependency.map { |v|
+ src = "#{current_build_dir}/#{v}.cxx"
+ file src => "#{current_dir}/#{v}.c" do |t|
+ File.open(t.name, 'w') do |f|
+ f.write <<EOS
+#define __STDC_CONSTANT_MACROS
+#define __STDC_LIMIT_MACROS
+
+extern "C" {
+#include "#{MRUBY_ROOT}/#{t.prerequisites.first}"
+}
+
+
+#{v == 'error'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''}
+EOS
+ end
+ end
+
+ file objfile(src) => src do |t|
+ cxx.run t.name, t.prerequisites.first, [], [current_dir]
+ end
+
+ objfile src
+ }
+ cxx_abi_objs << objfile("#{current_build_dir}/y.tab")
+
+ file "#{current_build_dir}/y.tab.cxx" => "#{current_build_dir}/y.tab.c" do |t|
+ File.open(t.name, 'w') do |f|
+ f.write <<EOS
+#define __STDC_CONSTANT_MACROS
+#define __STDC_LIMIT_MACROS
+
+extern "C" {
+#include "#{t.prerequisites.first}"
+}
+EOS
+ end
+ end
+ file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.cxx", lex_def] do |t|
+ cxx.run t.name, t.prerequisites.first, [], [current_dir]
+ end
+
+ objs += cxx_abi_objs
+ else
+ objs += [objfile("#{current_build_dir}/y.tab")]
+ file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.c", lex_def] do |t|
+ cc.run t.name, t.prerequisites.first, [], [current_dir]
+ end
+ end
self.libmruby << objs
file libfile("#{build_dir}/lib/libmruby_core") => objs do |t|
@@ -17,10 +71,6 @@ MRuby.each_target do
yacc.run t.name, t.prerequisites.first
end
- file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.c", lex_def] do |t|
- cc.run t.name, t.prerequisites.first, [], [current_dir]
- end
-
# Lexical analyzer
file lex_def => "#{current_dir}/keywords" do |t|
gperf.run t.name, t.prerequisites.first
diff --git a/src/node.h b/src/node.h
index df27c431f..532a8323a 100644
--- a/src/node.h
+++ b/src/node.h
@@ -8,110 +8,110 @@
#define NODE_H
enum node_type {
- NODE_METHOD,
- NODE_FBODY,
- NODE_CFUNC,
- NODE_SCOPE,
- NODE_BLOCK,
- NODE_IF,
- NODE_CASE,
- NODE_WHEN,
- NODE_OPT_N,
- NODE_WHILE,
- NODE_UNTIL,
- NODE_ITER,
- NODE_FOR,
- NODE_BREAK,
- NODE_NEXT,
- NODE_REDO,
- NODE_RETRY,
- NODE_BEGIN,
- NODE_RESCUE,
- NODE_ENSURE,
- NODE_AND,
- NODE_OR,
- NODE_NOT,
- NODE_MASGN,
- NODE_ASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_CVDECL,
- NODE_OP_ASGN,
- NODE_CALL,
- NODE_FCALL,
- NODE_VCALL,
- NODE_SUPER,
- NODE_ZSUPER,
- NODE_ARRAY,
- NODE_ZARRAY,
- NODE_HASH,
- NODE_RETURN,
- NODE_YIELD,
- NODE_LVAR,
- NODE_DVAR,
- NODE_GVAR,
- NODE_IVAR,
- NODE_CONST,
- NODE_CVAR,
- NODE_NTH_REF,
- NODE_BACK_REF,
- NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
- NODE_INT,
- NODE_FLOAT,
- NODE_NEGATE,
- NODE_LAMBDA,
- NODE_SYM,
- NODE_STR,
- NODE_DSTR,
- NODE_XSTR,
- NODE_DXSTR,
- NODE_REGX,
- NODE_DREGX,
- NODE_DREGX_ONCE,
- NODE_LIST,
- NODE_ARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
- NODE_SPLAT,
- NODE_TO_ARY,
- NODE_SVALUE,
- NODE_BLOCK_ARG,
- NODE_DEF,
- NODE_SDEF,
- NODE_ALIAS,
- NODE_UNDEF,
- NODE_CLASS,
- NODE_MODULE,
- NODE_SCLASS,
- NODE_COLON2,
- NODE_COLON3,
- NODE_CREF,
- NODE_DOT2,
- NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_ATTRSET,
- NODE_SELF,
- NODE_NIL,
- NODE_TRUE,
- NODE_FALSE,
- NODE_DEFINED,
- NODE_NEWLINE,
- NODE_POSTEXE,
- NODE_ALLOCA,
- NODE_DMETHOD,
- NODE_BMETHOD,
- NODE_MEMO,
- NODE_IFUNC,
- NODE_DSYM,
- NODE_ATTRASGN,
- NODE_HEREDOC,
- NODE_LITERAL_DELIM,
- NODE_WORDS,
- NODE_SYMBOLS,
- NODE_LAST
+ NODE_METHOD,
+ NODE_FBODY,
+ NODE_CFUNC,
+ NODE_SCOPE,
+ NODE_BLOCK,
+ NODE_IF,
+ NODE_CASE,
+ NODE_WHEN,
+ NODE_OPT_N,
+ NODE_WHILE,
+ NODE_UNTIL,
+ NODE_ITER,
+ NODE_FOR,
+ NODE_BREAK,
+ NODE_NEXT,
+ NODE_REDO,
+ NODE_RETRY,
+ NODE_BEGIN,
+ NODE_RESCUE,
+ NODE_ENSURE,
+ NODE_AND,
+ NODE_OR,
+ NODE_NOT,
+ NODE_MASGN,
+ NODE_ASGN,
+ NODE_CDECL,
+ NODE_CVASGN,
+ NODE_CVDECL,
+ NODE_OP_ASGN,
+ NODE_CALL,
+ NODE_FCALL,
+ NODE_VCALL,
+ NODE_SUPER,
+ NODE_ZSUPER,
+ NODE_ARRAY,
+ NODE_ZARRAY,
+ NODE_HASH,
+ NODE_RETURN,
+ NODE_YIELD,
+ NODE_LVAR,
+ NODE_DVAR,
+ NODE_GVAR,
+ NODE_IVAR,
+ NODE_CONST,
+ NODE_CVAR,
+ NODE_NTH_REF,
+ NODE_BACK_REF,
+ NODE_MATCH,
+ NODE_MATCH2,
+ NODE_MATCH3,
+ NODE_INT,
+ NODE_FLOAT,
+ NODE_NEGATE,
+ NODE_LAMBDA,
+ NODE_SYM,
+ NODE_STR,
+ NODE_DSTR,
+ NODE_XSTR,
+ NODE_DXSTR,
+ NODE_REGX,
+ NODE_DREGX,
+ NODE_DREGX_ONCE,
+ NODE_LIST,
+ NODE_ARG,
+ NODE_ARGSCAT,
+ NODE_ARGSPUSH,
+ NODE_SPLAT,
+ NODE_TO_ARY,
+ NODE_SVALUE,
+ NODE_BLOCK_ARG,
+ NODE_DEF,
+ NODE_SDEF,
+ NODE_ALIAS,
+ NODE_UNDEF,
+ NODE_CLASS,
+ NODE_MODULE,
+ NODE_SCLASS,
+ NODE_COLON2,
+ NODE_COLON3,
+ NODE_CREF,
+ NODE_DOT2,
+ NODE_DOT3,
+ NODE_FLIP2,
+ NODE_FLIP3,
+ NODE_ATTRSET,
+ NODE_SELF,
+ NODE_NIL,
+ NODE_TRUE,
+ NODE_FALSE,
+ NODE_DEFINED,
+ NODE_NEWLINE,
+ NODE_POSTEXE,
+ NODE_ALLOCA,
+ NODE_DMETHOD,
+ NODE_BMETHOD,
+ NODE_MEMO,
+ NODE_IFUNC,
+ NODE_DSYM,
+ NODE_ATTRASGN,
+ NODE_HEREDOC,
+ NODE_LITERAL_DELIM,
+ NODE_WORDS,
+ NODE_SYMBOLS,
+ NODE_LAST
};
#endif /* NODE_H */
diff --git a/src/numeric.c b/src/numeric.c
index cfde61c8c..ef9308aea 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -5,12 +5,6 @@
*/
#include <float.h>
-#if defined(__FreeBSD__) && __FreeBSD__ < 4
-# include <floatingpoint.h>
-#endif
-#ifdef HAVE_IEEEFP_H
-# include <ieeefp.h>
-#endif
#include <limits.h>
#include <math.h>
#include <stdlib.h>
@@ -23,11 +17,17 @@
#ifdef MRB_USE_FLOAT
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
-#define floor(f) floorf(f)
#define fmod(x,y) fmodf(x,y)
+#define FLO_MAX_DIGITS 7
+#define FLO_MAX_SIGN_LENGTH 3
+#define FLO_EPSILON FLT_EPSILON
+#else
+#define FLO_MAX_DIGITS 14
+#define FLO_MAX_SIGN_LENGTH 10
+#define FLO_EPSILON DBL_EPSILON
#endif
-static mrb_float
+mrb_float
mrb_to_flo(mrb_state *mrb, mrb_value val)
{
switch (mrb_type(val)) {
@@ -42,38 +42,6 @@ mrb_to_flo(mrb_state *mrb, mrb_value val)
}
/*
- * call-seq:
- * +num -> num
- *
- * Unary Plus---Returns the receiver's value.
- */
-
-static mrb_value
-num_uplus(mrb_state *mrb, mrb_value num)
-{
- return num;
-}
-
-/*
- * call-seq:
- * -num -> numeric
- *
- * Unary Minus---Returns the receiver's value, negated.
- */
-
-static mrb_value
-num_uminus(mrb_state *mrb, mrb_value num)
-{
- return mrb_float_value(mrb, (mrb_float)0 - mrb_to_flo(mrb, num));
-}
-
-static mrb_value
-fix_uminus(mrb_state *mrb, mrb_value num)
-{
- return mrb_fixnum_value(0 - mrb_fixnum(num));
-}
-
-/*
* call-seq:
*
* num ** other -> num
@@ -86,7 +54,7 @@ static mrb_value
num_pow(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- int both_int = FALSE;
+ mrb_bool both_int = FALSE;
mrb_float d;
mrb_get_args(mrb, "o", &y);
@@ -131,27 +99,6 @@ num_div(mrb_state *mrb, mrb_value x)
return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
}
-/*
- * call-seq:
- * num.abs -> numeric
- * num.magnitude -> numeric
- *
- * Returns the absolute value of <i>num</i>.
- *
- * 12.abs #=> 12
- * (-34.56).abs #=> 34.56
- * -34.56.abs #=> 34.56
- */
-
-static mrb_value
-num_abs(mrb_state *mrb, mrb_value num)
-{
- if (mrb_to_flo(mrb, num) < 0) {
- return num_uminus(mrb, num);
- }
- return num;
-}
-
/********************************************************************
*
* Document-class: Float
@@ -161,78 +108,115 @@ num_abs(mrb_state *mrb, mrb_value num)
* representation.
*/
-mrb_value
-mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit)
+static mrb_value
+mrb_flo_to_str(mrb_state *mrb, mrb_float flo)
{
- mrb_value result;
- mrb_float n;
-
- if (max_digit > 40) {
- mrb_raise(mrb, E_RANGE_ERROR, "Too large max_digit.");
- }
- else if (!mrb_float_p(flo)) {
- mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- }
-
- n = mrb_float(flo);
+ double n = (double)flo;
+ int max_digits = FLO_MAX_DIGITS;
if (isnan(n)) {
- result = mrb_str_new(mrb, "NaN", 3);
+ return mrb_str_new_lit(mrb, "NaN");
}
else if (isinf(n)) {
if (n < 0) {
- result = mrb_str_new(mrb, "-inf", 4);
+ return mrb_str_new_lit(mrb, "-inf");
}
else {
- result = mrb_str_new(mrb, "inf", 3);
+ return mrb_str_new_lit(mrb, "inf");
}
}
else {
int digit;
- int m;
+ int m = 0;
int exp;
- int e = 0;
+ mrb_bool e = FALSE;
char s[48];
char *c = &s[0];
+ int length = 0;
- if (n < 0) {
+ if (signbit(n)) {
n = -n;
*(c++) = '-';
}
- exp = log10(n);
+ if (n != 0.0) {
+ if (n > 1.0) {
+ exp = (int)floor(log10(n));
+ }
+ else {
+ exp = (int)-ceil(-log10(n));
+ }
+ }
+ else {
+ exp = 0;
+ }
+
+ /* preserve significands */
+ if (exp < 0) {
+ int i, beg = -1, end = 0;
+ double f = n;
+ double fd = 0;
+ for (i = 0; i < FLO_MAX_DIGITS; ++i) {
+ f = (f - fd) * 10.0;
+ fd = floor(f + FLO_EPSILON);
+ if (fd != 0) {
+ if (beg < 0) beg = i;
+ end = i + 1;
+ }
+ }
+ if (beg >= 0) length = end - beg;
+ if (length > FLO_MAX_SIGN_LENGTH) length = FLO_MAX_SIGN_LENGTH;
+ }
- if ((exp < 0 ? -exp : exp) > max_digit) {
+ if (abs(exp) + length >= FLO_MAX_DIGITS) {
/* exponent representation */
- e = 1;
- m = exp;
- if (m < 0) {
- m -= 1;
+ e = TRUE;
+ n = n / pow(10.0, exp);
+ if (isinf(n)) {
+ if (s < c) { /* s[0] == '-' */
+ return mrb_str_new_lit(mrb, "-0.0");
+ }
+ else {
+ return mrb_str_new_lit(mrb, "0.0");
+ }
}
- n = n / pow(10.0, m);
- m = 0;
}
else {
/* un-exponent (normal) representation */
- m = exp;
- if (m < 0) {
- m = 0;
+ if (exp > 0) {
+ m = exp;
}
}
/* puts digits */
- while (max_digit >= 0) {
- mrb_float weight = pow(10.0, m);
- digit = floor(n / weight + FLT_EPSILON);
+ while (max_digits >= 0) {
+ double weight = pow(10.0, m);
+ double fdigit = n / weight;
+
+ if (fdigit < 0) fdigit = n = 0;
+ if (m < -1 && fdigit < FLO_EPSILON) {
+ if (e || exp > 0 || m <= -abs(exp)) {
+ break;
+ }
+ }
+ digit = (int)floor(fdigit + FLO_EPSILON);
+ if (m == 0 && digit > 9) {
+ n /= 10.0;
+ exp++;
+ continue;
+ }
*(c++) = '0' + digit;
n -= (digit * weight);
- max_digit--;
+ max_digits--;
if (m-- == 0) {
*(c++) = '.';
}
- else if (m < -1 && n < FLT_EPSILON) {
- break;
+ }
+ if (c[-1] == '0') {
+ while (&s[0] < c && c[-1] == '0') {
+ c--;
}
+ c++;
}
if (e) {
@@ -246,7 +230,8 @@ mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit)
}
if (exp >= 100) {
- mrb_raise(mrb, E_RANGE_ERROR, "Too large expornent.");
+ *(c++) = '0' + exp / 100;
+ exp -= exp / 100 * 100;
}
*(c++) = '0' + exp / 10;
@@ -255,10 +240,8 @@ mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit)
*c = '\0';
- result = mrb_str_new(mrb, &s[0], c - &s[0]);
+ return mrb_str_new(mrb, &s[0], c - &s[0]);
}
-
- return result;
}
/* 15.2.9.3.16(x) */
@@ -275,11 +258,7 @@ mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit)
static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
-#ifdef MRB_USE_FLOAT
- return mrb_flo_to_str(mrb, flt, 7);
-#else
- return mrb_flo_to_str(mrb, flt, 14);
-#endif
+ return mrb_flo_to_str(mrb, mrb_float(flt));
}
/* 15.2.9.3.2 */
@@ -325,8 +304,8 @@ flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *
mrb_float mod;
if (y == 0.0) {
- div = str_to_mrb_float("inf");
- mod = str_to_mrb_float("nan");
+ div = INFINITY;
+ mod = NAN;
}
else {
mod = fmod(x, y);
@@ -382,27 +361,23 @@ flo_mod(mrb_state *mrb, mrb_value x)
* (1.0).eql?(1.0) #=> true
*/
static mrb_value
-num_eql(mrb_state *mrb, mrb_value x)
+fix_eql(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_bool eql_p;
mrb_get_args(mrb, "o", &y);
- if (mrb_type(x) != mrb_type(y)) {
- eql_p = 0;
- }
- else {
- eql_p = mrb_equal(mrb, x, y);
- }
-
- return mrb_bool_value(eql_p);
+ if (!mrb_fixnum_p(y)) return mrb_false_value();
+ return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
}
static mrb_value
-num_equal(mrb_state *mrb, mrb_value x, mrb_value y)
+flo_eql(mrb_state *mrb, mrb_value x)
{
- if (mrb_obj_equal(mrb, x, y)) return mrb_true_value();
- return mrb_funcall(mrb, y, "==", 1, x);
+ mrb_value y;
+
+ mrb_get_args(mrb, "o", &y);
+ if (!mrb_float_p(y)) return mrb_false_value();
+ return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
}
/* 15.2.9.3.7 */
@@ -434,7 +409,7 @@ flo_eq(mrb_state *mrb, mrb_value x)
b = mrb_float(y);
break;
default:
- return num_equal(mrb, x, y);
+ return mrb_false_value();
}
a = mrb_float(x);
return mrb_bool_value(a == b);
@@ -615,6 +590,16 @@ flo_round(mrb_state *mrb, mrb_value num)
mrb_get_args(mrb, "|i", &ndigits);
number = mrb_float(num);
+
+ if (isinf(number)) {
+ if (0 < ndigits) return num;
+ else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, number < 0 ? "-Infinity" : "Infinity");
+ }
+ if (isnan(number)) {
+ if (0 < ndigits) return num;
+ else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
+ }
+
f = 1.0;
i = abs(ndigits);
while (--i >= 0)
@@ -642,7 +627,11 @@ flo_round(mrb_state *mrb, mrb_value num)
if (ndigits < 0) number *= f;
else number /= f;
}
- if (ndigits > 0) return mrb_float_value(mrb, number);
+
+ if (ndigits > 0) {
+ if (isinf(number) || isnan(number)) return num;
+ return mrb_float_value(mrb, number);
+ }
return mrb_fixnum_value((mrb_int)number);
}
@@ -671,6 +660,12 @@ flo_truncate(mrb_state *mrb, mrb_value num)
return mrb_fixnum_value((mrb_int)f);
}
+static mrb_value
+flo_nan_p(mrb_state *mrb, mrb_value num)
+{
+ return mrb_bool_value(isnan(mrb_float(num)));
+}
+
/*
* Document-class: Integer
*
@@ -695,43 +690,7 @@ int_to_i(mrb_state *mrb, mrb_value num)
return num;
}
-/* 15.2.8.3.21 */
-/*
- * call-seq:
- * fixnum.next -> integer
- * fixnum.succ -> integer
- *
- * Returns the <code>Integer</code> equal to <i>int</i> + 1.
- *
- * 1.next #=> 2
- * (-1).next #=> 0
- */
-
-static mrb_value
-fix_succ(mrb_state *mrb, mrb_value num)
-{
- return mrb_fixnum_value(mrb_fixnum(num)+1);
-}
-
-/* 15.2.8.3.19 */
-/*
- * call-seq:
- * int.next -> integer
- * int.succ -> integer
- *
- * Returns the <code>Integer</code> equal to <i>int</i> + 1.
- *
- * 1.next #=> 2
- * (-1).next #=> 0
- */
-static mrb_value
-int_succ(mrb_state *mrb, mrb_value num)
-{
- if (mrb_fixnum_p(num)) return fix_succ(mrb, num);
- return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1));
-}
-
-#define SQRT_INT_MAX ((mrb_int)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
+#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1)/2))
/*tests if N*N would overflow*/
#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
@@ -741,10 +700,10 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
mrb_int a;
a = mrb_fixnum(x);
- if (a == 0) return x;
if (mrb_fixnum_p(y)) {
mrb_int b, c;
+ if (a == 0) return x;
b = mrb_fixnum(y);
if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
return mrb_fixnum_value(a*b);
@@ -752,7 +711,7 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
if (a != 0 && c/a != b) {
return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b);
}
- return mrb_fixnum_value(c);;
+ return mrb_fixnum_value(c);
}
return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
}
@@ -826,7 +785,7 @@ fix_mod(mrb_state *mrb, mrb_value x)
mrb_int mod;
if (mrb_fixnum(y) == 0) {
- return mrb_float_value(mrb, str_to_mrb_float("nan"));
+ return mrb_float_value(mrb, NAN);
}
fixdivmod(mrb, a, mrb_fixnum(y), 0, &mod);
return mrb_fixnum_value(mod);
@@ -856,8 +815,8 @@ fix_divmod(mrb_state *mrb, mrb_value x)
mrb_int div, mod;
if (mrb_fixnum(y) == 0) {
- return mrb_assoc_new(mrb, mrb_float_value(mrb, str_to_mrb_float("inf")),
- mrb_float_value(mrb, str_to_mrb_float("nan")));
+ return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
+ mrb_float_value(mrb, NAN));
}
fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
@@ -873,6 +832,21 @@ fix_divmod(mrb_state *mrb, mrb_value x)
}
}
+static mrb_value
+flo_divmod(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y;
+ mrb_float div, mod;
+ mrb_value a, b;
+
+ mrb_get_args(mrb, "o", &y);
+
+ flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
+ a = mrb_float_value(mrb, (mrb_int)div);
+ b = mrb_float_value(mrb, mod);
+ return mrb_assoc_new(mrb, a, b);
+}
+
/* 15.2.8.3.7 */
/*
* call-seq:
@@ -889,15 +863,16 @@ static mrb_value
fix_equal(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_bool equal_p;
mrb_get_args(mrb, "o", &y);
-
- equal_p = mrb_obj_equal(mrb, x, y) ||
- (mrb_type(y) == MRB_TT_FLOAT &&
- (mrb_float)mrb_fixnum(x) == mrb_float(y));
-
- return mrb_bool_value(equal_p);
+ switch (mrb_type(y)) {
+ case MRB_TT_FIXNUM:
+ return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
+ case MRB_TT_FLOAT:
+ return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
+ default:
+ return mrb_false_value();
+ }
}
/* 15.2.8.3.8 */
@@ -914,22 +889,21 @@ fix_equal(mrb_state *mrb, mrb_value x)
static mrb_value
fix_rev(mrb_state *mrb, mrb_value num)
{
- mrb_int val = mrb_fixnum(num);
+ mrb_int val = mrb_fixnum(num);
- val = ~val;
- return mrb_fixnum_value(val);
+ return mrb_fixnum_value(~val);
}
static mrb_value
bit_coerce(mrb_state *mrb, mrb_value x)
{
- while (!mrb_fixnum_p(x)) {
- if (mrb_float_p(x)) {
- mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
- }
- x = mrb_to_int(mrb, x);
+ while (!mrb_fixnum_p(x)) {
+ if (mrb_float_p(x)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
}
- return x;
+ x = mrb_to_int(mrb, x);
+ }
+ return x;
}
/* 15.2.8.3.9 */
@@ -995,13 +969,14 @@ fix_xor(mrb_state *mrb, mrb_value x)
return mrb_fixnum_value(val);
}
-#define NUMERIC_SHIFT_WIDTH_MAX (sizeof(mrb_int)*CHAR_BIT-1)
+#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
static mrb_value
-lshift(mrb_state *mrb, mrb_int val, size_t width)
+lshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
+ mrb_assert(width >= 0);
if (width > NUMERIC_SHIFT_WIDTH_MAX) {
- mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:sizeof(mrb_int)*CHAR_BIT-1)",
+ mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)",
mrb_fixnum_value(width),
mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX));
}
@@ -1010,8 +985,9 @@ lshift(mrb_state *mrb, mrb_int val, size_t width)
}
static mrb_value
-rshift(mrb_int val, size_t width)
+rshift(mrb_int val, mrb_int width)
{
+ mrb_assert(width >= 0);
if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
if (val < 0) {
val = -1;
@@ -1048,27 +1024,18 @@ fix_shift_get_width(mrb_state *mrb, mrb_int *width)
static mrb_value
fix_lshift(mrb_state *mrb, mrb_value x)
{
- mrb_int width;
- mrb_value result;
+ mrb_int width, val;
fix_shift_get_width(mrb, &width);
if (width == 0) {
- result = x;
+ return x;
}
- else {
- mrb_int val;
-
- val = mrb_fixnum(x);
- if (width < 0) {
- result = rshift(val, -width);
- }
- else {
- result = lshift(mrb, val, width);
- }
+ val = mrb_fixnum(x);
+ if (width < 0) {
+ return rshift(val, -width);
}
-
- return result;
+ return lshift(mrb, val, width);
}
/* 15.2.8.3.13 */
@@ -1082,27 +1049,18 @@ fix_lshift(mrb_state *mrb, mrb_value x)
static mrb_value
fix_rshift(mrb_state *mrb, mrb_value x)
{
- mrb_int width;
- mrb_value result;
+ mrb_int width, val;
fix_shift_get_width(mrb, &width);
if (width == 0) {
- result = x;
+ return x;
}
- else {
- mrb_int val;
-
- val = mrb_fixnum(x);
- if (width < 0) {
- result = lshift(mrb, val, -width);
- }
- else {
- result = rshift(val, width);
- }
+ val = mrb_fixnum(x);
+ if (width < 0) {
+ return lshift(mrb, val, -width);
}
-
- return result;
+ return rshift(val, width);
}
/* 15.2.8.3.23 */
@@ -1145,7 +1103,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
if (mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- z = 0; /* not reached. just supress warnings. */
+ z = 0; /* not reached. just suppress warnings. */
}
else {
mrb_float d = mrb_float(x);
@@ -1167,10 +1125,10 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
mrb_int a;
a = mrb_fixnum(x);
- if (a == 0) return y;
if (mrb_fixnum_p(y)) {
mrb_int b, c;
+ if (a == 0) return y;
b = mrb_fixnum(y);
c = a + b;
if (((a < 0) ^ (b < 0)) == 0 && (a < 0) != (c < 0)) {
@@ -1243,7 +1201,7 @@ fix_minus(mrb_state *mrb, mrb_value self)
mrb_value
mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
{
- char buf[sizeof(mrb_int)*CHAR_BIT+1];
+ char buf[MRB_INT_BIT+1];
char *b = buf + sizeof buf;
mrb_int val = mrb_fixnum(x);
@@ -1342,15 +1300,14 @@ num_cmp(mrb_state *mrb, mrb_value self)
* and <code>other</code>.
*/
static mrb_value
-flo_plus(mrb_state *mrb, mrb_value self)
+flo_plus(mrb_state *mrb, mrb_value x)
{
- mrb_float x, y;
-
- x = mrb_float(self);
- mrb_get_args(mrb, "f", &y);
+ mrb_value y;
- return mrb_float_value(mrb, x + y);
+ mrb_get_args(mrb, "o", &y);
+ return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
}
+
/* ------------------------------------------------------------------------*/
void
mrb_init_numeric(mrb_state *mrb)
@@ -1359,26 +1316,21 @@ mrb_init_numeric(mrb_state *mrb)
/* Numeric Class */
numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
- mrb_include_module(mrb, numeric, mrb_class_get(mrb, "Comparable"));
- mrb_define_method(mrb, numeric, "+@", num_uplus, MRB_ARGS_REQ(1)); /* 15.2.7.4.1 */
- mrb_define_method(mrb, numeric, "-@", num_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
- mrb_define_method(mrb, numeric, "abs", num_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */
mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
/* Integer Class */
integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
mrb_undef_class_method(mrb, integer, "new");
- mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
+ mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
- fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
+ fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
- mrb_define_method(mrb, fixnum, "-@", fix_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
@@ -1388,10 +1340,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
- mrb_define_method(mrb, fixnum, "eql?", num_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
+ mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
- mrb_define_method(mrb, fixnum, "next", int_succ, MRB_ARGS_NONE()); /* 15.2.8.3.19 */
- mrb_define_method(mrb, fixnum, "succ", fix_succ, MRB_ARGS_NONE()); /* 15.2.8.3.21 */
mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
@@ -1409,12 +1359,15 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
- mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_NONE()); /* 15.2.9.3.12 */
+ mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
+ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
}
diff --git a/src/object.c b/src/object.c
index 5b2278767..6d39254dd 100644
--- a/src/object.c
+++ b/src/object.c
@@ -5,11 +5,9 @@
*/
#include "mruby.h"
-#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/numeric.h"
#include "mruby/string.h"
-#include "error.h"
mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
@@ -29,7 +27,7 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
return (mrb_float(v1) == mrb_float(v2));
default:
- return (v1.value.p == v2.value.p);
+ return (mrb_ptr(v1) == mrb_ptr(v2));
}
}
@@ -88,7 +86,7 @@ nil_to_s(mrb_state *mrb, mrb_value obj)
static mrb_value
nil_inspect(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new(mrb, "nil", 3);
+ return mrb_str_new_lit(mrb, "nil");
}
/***********************************************************************
@@ -149,7 +147,7 @@ true_xor(mrb_state *mrb, mrb_value obj)
static mrb_value
true_to_s(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new(mrb, "true", 4);
+ return mrb_str_new_lit(mrb, "true");
}
/* 15.2.5.3.4 */
@@ -256,7 +254,7 @@ false_or(mrb_state *mrb, mrb_value obj)
static mrb_value
false_to_s(mrb_state *mrb, mrb_value obj)
{
- return mrb_str_new(mrb, "false", 5);
+ return mrb_str_new_lit(mrb, "false");
}
void
@@ -293,14 +291,25 @@ mrb_init_object(mrb_state *mrb)
}
static mrb_value
-convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, int raise)
+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;
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", val, mrb_str_new_cstr(mrb, tname));
+ mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname));
return mrb_nil_value();
}
else {
@@ -315,9 +324,9 @@ mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method)
{
mrb_value v;
- if (mrb_type(val) == MRB_TT_FIXNUM) return val;
+ if (mrb_fixnum_p(val)) return val;
v = convert_type(mrb, val, "Integer", method, FALSE);
- if (mrb_nil_p(v) || mrb_type(v) != MRB_TT_FIXNUM) {
+ if (mrb_nil_p(v) || !mrb_fixnum_p(v)) {
return mrb_nil_value();
}
return v;
@@ -329,7 +338,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char
mrb_value v;
if (mrb_type(val) == type) return val;
- v = convert_type(mrb, val, tname, method, 1/*Qtrue*/);
+ 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));
@@ -343,7 +352,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const
mrb_value v;
if (mrb_type(val) == type && type != MRB_TT_DATA) return val;
- v = convert_type(mrb, val, tname, method, 0/*Qfalse*/);
+ v = convert_type(mrb, val, tname, method, FALSE);
if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value();
return v;
}
@@ -352,7 +361,7 @@ static const struct types {
unsigned char type;
const char *name;
} builtin_types[] = {
-// {MRB_TT_NIL, "nil"},
+/* {MRB_TT_NIL, "nil"}, */
{MRB_TT_FALSE, "false"},
{MRB_TT_TRUE, "true"},
{MRB_TT_FIXNUM, "Fixnum"},
@@ -368,12 +377,12 @@ static const struct types {
{MRB_TT_HASH, "Hash"},
{MRB_TT_STRING, "String"},
{MRB_TT_RANGE, "Range"},
-// {MRB_TT_BIGNUM, "Bignum"},
+/* {MRB_TT_BIGNUM, "Bignum"}, */
{MRB_TT_FILE, "File"},
{MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */
-// {MRB_TT_VARMAP, "Varmap"}, /* internal use: dynamic variables */
-// {MRB_TT_NODE, "Node"}, /* internal use: syntax tree node */
-// {MRB_TT_UNDEF, "undef"}, /* internal use: #undef; should not happen */
+/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */
+/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */
+/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */
{-1, 0}
};
@@ -381,7 +390,6 @@ void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
const struct types *type = builtin_types;
- struct RString *s;
enum mrb_vtype xt;
xt = mrb_type(x);
@@ -393,15 +401,14 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
if (mrb_nil_p(x)) {
etype = "nil";
}
- else if (mrb_type(x) == MRB_TT_FIXNUM) {
+ else if (mrb_fixnum_p(x)) {
etype = "Fixnum";
}
else if (mrb_type(x) == MRB_TT_SYMBOL) {
etype = "Symbol";
}
else if (mrb_special_const_p(x)) {
- s = mrb_str_ptr(mrb_obj_as_string(mrb, x));
- etype = s->ptr;
+ etype = RSTRING_PTR(mrb_obj_as_string(mrb, x));
}
else {
etype = mrb_obj_classname(mrb, x);
@@ -433,11 +440,11 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
mrb_value str = mrb_str_buf_new(mrb, 20);
const char *cname = mrb_obj_classname(mrb, obj);
- mrb_str_buf_cat(mrb, str, "#<", 2);
- mrb_str_cat2(mrb, str, cname);
- mrb_str_cat(mrb, str, ":", 1);
- mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_voidp(obj)));
- mrb_str_buf_cat(mrb, str, ">", 1);
+ mrb_str_cat_lit(mrb, str, "#<");
+ mrb_str_cat_cstr(mrb, str, cname);
+ mrb_str_cat_lit(mrb, str, ":");
+ mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj)));
+ mrb_str_cat_lit(mrb, str, ">");
return str;
}
@@ -499,8 +506,9 @@ mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method)
if (mrb_fixnum_p(val)) return val;
v = convert_type(mrb, val, "Integer", method, TRUE);
if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) {
+ mrb_value type = inspect_type(mrb, val);
mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)",
- val, val, mrb_str_new_cstr(mrb, method), v);
+ type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v));
}
return v;
}
@@ -532,16 +540,14 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
if (base != 0) goto arg_error;
return val;
- case MRB_TT_STRING:
-string_conv:
- return mrb_str_to_inum(mrb, val, base, TRUE);
-
default:
break;
}
if (base != 0) {
tmp = mrb_check_string_type(mrb, val);
- if (!mrb_nil_p(tmp)) goto string_conv;
+ if (!mrb_nil_p(tmp)) {
+ return mrb_str_to_inum(mrb, val, base, TRUE);
+ }
arg_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
}
@@ -582,7 +588,7 @@ mrb_Float(mrb_state *mrb, mrb_value val)
mrb_value
mrb_inspect(mrb_state *mrb, mrb_value obj)
{
- return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0, 0));
+ return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0));
}
mrb_bool
diff --git a/src/opcode.h b/src/opcode.h
index f87611119..7b5196d31 100644
--- a/src/opcode.h
+++ b/src/opcode.h
@@ -73,8 +73,8 @@ enum {
OP_SETCV,/* A Bx cvset(Sym(Bx),R(A)) */
OP_GETCONST,/* A Bx R(A) := constget(Sym(Bx)) */
OP_SETCONST,/* A Bx constset(Sym(Bx),R(A)) */
- OP_GETMCNST,/* A Bx R(A) := R(A)::Sym(B) */
- OP_SETMCNST,/* A Bx R(A+1)::Sym(B) := R(A) */
+ OP_GETMCNST,/* A Bx R(A) := R(A)::Sym(Bx) */
+ OP_SETMCNST,/* A Bx R(A+1)::Sym(Bx) := R(A) */
OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */
OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */
@@ -125,7 +125,7 @@ enum {
OP_STRCAT,/* A B str_cat(R(A),R(B)) */
OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
- OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cm) */
+ OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */
OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */
OP_OCLASS,/* A R(A) := ::Object */
diff --git a/src/parse.y b/src/parse.y
index 4fa9e70de..345ac5756 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -24,7 +24,9 @@
#include "mruby.h"
#include "mruby/compile.h"
#include "mruby/proc.h"
+#include "mruby/error.h"
#include "node.h"
+#include "mrb_throw.h"
#define YYLEX_PARAM p
@@ -32,11 +34,13 @@ typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
typedef struct mrb_parser_heredoc_info parser_heredoc_info;
+static int yyparse(parser_state *p);
static int yylex(void *lval, parser_state *p);
static void yyerror(parser_state *p, const char *s);
static void yywarn(parser_state *p, const char *s);
static void yywarning(parser_state *p, const char *s);
static void backref_error(parser_state *p, node *n);
+static void tokadd(parser_state *p, int32_t c);
#ifndef isascii
#define isascii(c) (((c) & ~0x7f) == 0)
@@ -61,27 +65,29 @@ typedef unsigned int stack_type;
#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack)
#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack)
+#define SET_LINENO(c,n) ((c)->lineno = (n))
+
#define sym(x) ((mrb_sym)(intptr_t)(x))
#define nsym(x) ((node*)(intptr_t)(x))
static inline mrb_sym
-intern_gen(parser_state *p, const char *s)
+intern_cstr_gen(parser_state *p, const char *s)
{
- return mrb_intern(p->mrb, s);
+ return mrb_intern_cstr(p->mrb, s);
}
-#define intern(s) intern_gen(p,(s))
+#define intern_cstr(s) intern_cstr_gen(p,(s))
static inline mrb_sym
-intern_gen2(parser_state *p, const char *s, size_t len)
+intern_gen(parser_state *p, const char *s, size_t len)
{
- return mrb_intern2(p->mrb, s, len);
+ return mrb_intern(p->mrb, s, len);
}
-#define intern2(s,len) intern_gen2(p,(s),(len))
+#define intern(s,len) intern_gen(p,(s),(len))
static inline mrb_sym
intern_gen_c(parser_state *p, const char c)
{
- return mrb_intern2(p->mrb, &c, 1);
+ return mrb_intern(p->mrb, &c, 1);
}
#define intern_c(c) intern_gen_c(p,(c))
@@ -99,7 +105,7 @@ parser_palloc(parser_state *p, size_t size)
void *m = mrb_pool_alloc(p->pool, size);
if (!m) {
- longjmp(p->jmp, 1);
+ MRB_THROW(p->jmp);
}
return m;
}
@@ -120,6 +126,7 @@ cons_gen(parser_state *p, node *car, node *cdr)
c->car = car;
c->cdr = cdr;
c->lineno = p->lineno;
+ c->filename_index = p->current_filename_index;
return c;
}
#define cons(a,b) cons_gen(p,(a),(b))
@@ -202,7 +209,7 @@ parser_strdup(parser_state *p, const char *s)
#undef strdup
#define strdup(s) parser_strdup(p, s)
-// xxx -----------------------------
+/* xxx ----------------------------- */
static node*
local_switch(parser_state *p)
@@ -261,14 +268,14 @@ local_add(parser_state *p, mrb_sym sym)
}
}
-// (:scope (vars..) (prog...))
+/* (:scope (vars..) (prog...)) */
static node*
new_scope(parser_state *p, node *body)
{
return cons((node*)NODE_SCOPE, cons(p->locals->car, body));
}
-// (:begin prog...)
+/* (:begin prog...) */
static node*
new_begin(parser_state *p, node *body)
{
@@ -279,84 +286,84 @@ new_begin(parser_state *p, node *body)
#define newline_node(n) (n)
-// (:rescue body rescue else)
+/* (:rescue body rescue else) */
static node*
new_rescue(parser_state *p, node *body, node *resq, node *els)
{
return list4((node*)NODE_RESCUE, body, resq, els);
}
-// (:ensure body ensure)
+/* (:ensure body ensure) */
static node*
new_ensure(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_ENSURE, cons(a, cons(0, b)));
}
-// (:nil)
+/* (:nil) */
static node*
new_nil(parser_state *p)
{
return list1((node*)NODE_NIL);
}
-// (:true)
+/* (:true) */
static node*
new_true(parser_state *p)
{
return list1((node*)NODE_TRUE);
}
-// (:false)
+/* (:false) */
static node*
new_false(parser_state *p)
{
return list1((node*)NODE_FALSE);
}
-// (:alias new old)
+/* (:alias new old) */
static node*
new_alias(parser_state *p, mrb_sym a, mrb_sym b)
{
return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b)));
}
-// (:if cond then else)
+/* (:if cond then else) */
static node*
new_if(parser_state *p, node *a, node *b, node *c)
{
return list4((node*)NODE_IF, a, b, c);
}
-// (:unless cond then else)
+/* (:unless cond then else) */
static node*
new_unless(parser_state *p, node *a, node *b, node *c)
{
return list4((node*)NODE_IF, a, c, b);
}
-// (:while cond body)
+/* (:while cond body) */
static node*
new_while(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_WHILE, cons(a, b));
}
-// (:until cond body)
+/* (:until cond body) */
static node*
new_until(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_UNTIL, cons(a, b));
}
-// (:for var obj body)
+/* (:for var obj body) */
static node*
new_for(parser_state *p, node *v, node *o, node *b)
{
return list4((node*)NODE_FOR, v, o, b);
}
-// (:case a ((when ...) body) ((when...) body))
+/* (:case a ((when ...) body) ((when...) body)) */
static node*
new_case(parser_state *p, node *a, node *b)
{
@@ -370,49 +377,49 @@ new_case(parser_state *p, node *a, node *b)
return n;
}
-// (:postexe a)
+/* (:postexe a) */
static node*
new_postexe(parser_state *p, node *a)
{
return cons((node*)NODE_POSTEXE, a);
}
-// (:self)
+/* (:self) */
static node*
new_self(parser_state *p)
{
return list1((node*)NODE_SELF);
}
-// (:call a b c)
+/* (:call a b c) */
static node*
new_call(parser_state *p, node *a, mrb_sym b, node *c)
{
return list4((node*)NODE_CALL, a, nsym(b), c);
}
-// (:fcall self mid args)
+/* (:fcall self mid args) */
static node*
new_fcall(parser_state *p, mrb_sym b, node *c)
{
return list4((node*)NODE_FCALL, new_self(p), nsym(b), c);
}
-// (:super . c)
+/* (:super . c) */
static node*
new_super(parser_state *p, node *c)
{
return cons((node*)NODE_SUPER, c);
}
-// (:zsuper)
+/* (:zsuper) */
static node*
new_zsuper(parser_state *p)
{
return list1((node*)NODE_ZSUPER);
}
-// (:yield . c)
+/* (:yield . c) */
static node*
new_yield(parser_state *p, node *c)
{
@@ -425,105 +432,105 @@ new_yield(parser_state *p, node *c)
return cons((node*)NODE_YIELD, 0);
}
-// (:return . c)
+/* (:return . c) */
static node*
new_return(parser_state *p, node *c)
{
return cons((node*)NODE_RETURN, c);
}
-// (:break . c)
+/* (:break . c) */
static node*
new_break(parser_state *p, node *c)
{
return cons((node*)NODE_BREAK, c);
}
-// (:next . c)
+/* (:next . c) */
static node*
new_next(parser_state *p, node *c)
{
return cons((node*)NODE_NEXT, c);
}
-// (:redo)
+/* (:redo) */
static node*
new_redo(parser_state *p)
{
return list1((node*)NODE_REDO);
}
-// (:retry)
+/* (:retry) */
static node*
new_retry(parser_state *p)
{
return list1((node*)NODE_RETRY);
}
-// (:dot2 a b)
+/* (:dot2 a b) */
static node*
new_dot2(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_DOT2, cons(a, b));
}
-// (:dot3 a b)
+/* (:dot3 a b) */
static node*
new_dot3(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_DOT3, cons(a, b));
}
-// (:colon2 b c)
+/* (:colon2 b c) */
static node*
new_colon2(parser_state *p, node *b, mrb_sym c)
{
return cons((node*)NODE_COLON2, cons(b, nsym(c)));
}
-// (:colon3 . c)
+/* (:colon3 . c) */
static node*
new_colon3(parser_state *p, mrb_sym c)
{
return cons((node*)NODE_COLON3, nsym(c));
}
-// (:and a b)
+/* (:and a b) */
static node*
new_and(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_AND, cons(a, b));
}
-// (:or a b)
+/* (:or a b) */
static node*
new_or(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_OR, cons(a, b));
}
-// (:array a...)
+/* (:array a...) */
static node*
new_array(parser_state *p, node *a)
{
return cons((node*)NODE_ARRAY, a);
}
-// (:splat . a)
+/* (:splat . a) */
static node*
new_splat(parser_state *p, node *a)
{
return cons((node*)NODE_SPLAT, a);
}
-// (:hash (k . v) (k . v)...)
+/* (:hash (k . v) (k . v)...) */
static node*
new_hash(parser_state *p, node *a)
{
return cons((node*)NODE_HASH, a);
}
-// (:sym . a)
+/* (:sym . a) */
static node*
new_sym(parser_state *p, mrb_sym sym)
{
@@ -536,99 +543,99 @@ new_strsym(parser_state *p, node* str)
const char *s = (const char*)str->cdr->car;
size_t len = (size_t)str->cdr->cdr;
- return mrb_intern2(p->mrb, s, len);
+ return mrb_intern(p->mrb, s, len);
}
-// (:lvar . a)
+/* (:lvar . a) */
static node*
new_lvar(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_LVAR, nsym(sym));
}
-// (:gvar . a)
+/* (:gvar . a) */
static node*
new_gvar(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_GVAR, nsym(sym));
}
-// (:ivar . a)
+/* (:ivar . a) */
static node*
new_ivar(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_IVAR, nsym(sym));
}
-// (:cvar . a)
+/* (:cvar . a) */
static node*
new_cvar(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_CVAR, nsym(sym));
}
-// (:const . a)
+/* (:const . a) */
static node*
new_const(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_CONST, nsym(sym));
}
-// (:undef a...)
+/* (:undef a...) */
static node*
new_undef(parser_state *p, mrb_sym sym)
{
return list2((node*)NODE_UNDEF, nsym(sym));
}
-// (:class class super body)
+/* (:class class super body) */
static node*
new_class(parser_state *p, node *c, node *s, node *b)
{
return list4((node*)NODE_CLASS, c, s, cons(p->locals->car, b));
}
-// (:sclass obj body)
+/* (:sclass obj body) */
static node*
new_sclass(parser_state *p, node *o, node *b)
{
return list3((node*)NODE_SCLASS, o, cons(p->locals->car, b));
}
-// (:module module body)
+/* (:module module body) */
static node*
new_module(parser_state *p, node *m, node *b)
{
return list3((node*)NODE_MODULE, m, cons(p->locals->car, b));
}
-// (:def m lv (arg . body))
+/* (:def m lv (arg . body)) */
static node*
new_def(parser_state *p, mrb_sym m, node *a, node *b)
{
return list5((node*)NODE_DEF, nsym(m), p->locals->car, a, b);
}
-// (:sdef obj m lv (arg . body))
+/* (:sdef obj m lv (arg . body)) */
static node*
new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b)
{
return list6((node*)NODE_SDEF, o, nsym(m), p->locals->car, a, b);
}
-// (:arg . sym)
+/* (:arg . sym) */
static node*
new_arg(parser_state *p, mrb_sym sym)
{
return cons((node*)NODE_ARG, nsym(sym));
}
-// (m o r m2 b)
-// m: (a b c)
-// o: ((a . e1) (b . e2))
-// r: a
-// m2: (a b c)
-// b: a
+/* (m o r m2 b) */
+/* m: (a b c) */
+/* o: ((a . e1) (b . e2)) */
+/* r: a */
+/* m2: (a b c) */
+/* b: a */
static node*
new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
{
@@ -640,126 +647,126 @@ new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym bl
return cons(m, n);
}
-// (:block_arg . a)
+/* (:block_arg . a) */
static node*
new_block_arg(parser_state *p, node *a)
{
return cons((node*)NODE_BLOCK_ARG, a);
}
-// (:block arg body)
+/* (:block arg body) */
static node*
new_block(parser_state *p, node *a, node *b)
{
return list4((node*)NODE_BLOCK, p->locals->car, a, b);
}
-// (:lambda arg body)
+/* (:lambda arg body) */
static node*
new_lambda(parser_state *p, node *a, node *b)
{
return list4((node*)NODE_LAMBDA, p->locals->car, a, b);
}
-// (:asgn lhs rhs)
+/* (:asgn lhs rhs) */
static node*
new_asgn(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_ASGN, cons(a, b));
}
-// (:masgn mlhs=(pre rest post) mrhs)
+/* (:masgn mlhs=(pre rest post) mrhs) */
static node*
new_masgn(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_MASGN, cons(a, b));
}
-// (:asgn lhs rhs)
+/* (:asgn lhs rhs) */
static node*
new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
{
return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
}
-// (:int . i)
+/* (:int . i) */
static node*
new_int(parser_state *p, const char *s, int base)
{
return list3((node*)NODE_INT, (node*)strdup(s), (node*)(intptr_t)base);
}
-// (:float . i)
+/* (:float . i) */
static node*
new_float(parser_state *p, const char *s)
{
return cons((node*)NODE_FLOAT, (node*)strdup(s));
}
-// (:str . (s . len))
+/* (:str . (s . len)) */
static node*
new_str(parser_state *p, const char *s, int len)
{
return cons((node*)NODE_STR, cons((node*)strndup(s, len), (node*)(intptr_t)len));
}
-// (:dstr . a)
+/* (:dstr . a) */
static node*
new_dstr(parser_state *p, node *a)
{
return cons((node*)NODE_DSTR, a);
}
-// (:str . (s . len))
+/* (:str . (s . len)) */
static node*
new_xstr(parser_state *p, const char *s, int len)
{
return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len));
}
-// (:xstr . a)
+/* (:xstr . a) */
static node*
new_dxstr(parser_state *p, node *a)
{
return cons((node*)NODE_DXSTR, a);
}
-// (:dsym . a)
+/* (:dsym . a) */
static node*
new_dsym(parser_state *p, node *a)
{
return cons((node*)NODE_DSYM, new_dstr(p, a));
}
-// (:str . (a . a))
+/* (:str . (a . a)) */
static node*
new_regx(parser_state *p, const char *p1, const char* p2)
{
return cons((node*)NODE_REGX, cons((node*)p1, (node*)p2));
}
-// (:dregx . a)
+/* (:dregx . a) */
static node*
new_dregx(parser_state *p, node *a, node *b)
{
return cons((node*)NODE_DREGX, cons(a, b));
}
-// (:backref . n)
+/* (:backref . n) */
static node*
new_back_ref(parser_state *p, int n)
{
return cons((node*)NODE_BACK_REF, (node*)(intptr_t)n);
}
-// (:nthref . n)
+/* (:nthref . n) */
static node*
new_nth_ref(parser_state *p, int n)
{
return cons((node*)NODE_NTH_REF, (node*)(intptr_t)n);
}
-// (:heredoc . a)
+/* (:heredoc . a) */
static node*
new_heredoc(parser_state *p)
{
@@ -778,34 +785,34 @@ new_literal_delim(parser_state *p)
return cons((node*)NODE_LITERAL_DELIM, 0);
}
-// (:words . a)
+/* (:words . a) */
static node*
new_words(parser_state *p, node *a)
{
return cons((node*)NODE_WORDS, a);
}
-// (:symbols . a)
+/* (:symbols . a) */
static node*
new_symbols(parser_state *p, node *a)
{
return cons((node*)NODE_SYMBOLS, a);
}
-// xxx -----------------------------
+/* xxx ----------------------------- */
-// (:call a op)
+/* (:call a op) */
static node*
-call_uni_op(parser_state *p, node *recv, char *m)
+call_uni_op(parser_state *p, node *recv, const char *m)
{
- return new_call(p, recv, intern(m), 0);
+ return new_call(p, recv, intern_cstr(m), 0);
}
-// (:call a op b)
+/* (:call a op b) */
static node*
-call_bin_op(parser_state *p, node *recv, char *m, node *arg1)
+call_bin_op(parser_state *p, node *recv, const char *m, node *arg1)
{
- return new_call(p, recv, intern(m), list1(list1(arg1)));
+ return new_call(p, recv, intern_cstr(m), list1(list1(arg1)));
}
static void
@@ -857,6 +864,7 @@ ret_args(parser_state *p, node *n)
{
if (n->cdr) {
yyerror(p, "block argument should not be given");
+ return NULL;
}
if (!n->car->cdr) return n->car->car;
return new_array(p, n->car);
@@ -903,7 +911,7 @@ end_strterm(parser_state *p)
p->lex_strterm = NULL;
}
-parser_heredoc_info *
+static parser_heredoc_info *
parsing_heredoc_inf(parser_state *p)
{
node *nd = p->parsing_heredoc;
@@ -914,6 +922,51 @@ parsing_heredoc_inf(parser_state *p)
}
static void
+heredoc_treat_nextline(parser_state *p)
+{
+ if (p->heredocs_from_nextline == NULL)
+ return;
+ if (p->parsing_heredoc == NULL) {
+ node *n;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ p->lex_strterm_before_heredoc = p->lex_strterm;
+ p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0);
+ n = p->all_heredocs;
+ if (n) {
+ while (n->cdr)
+ n = n->cdr;
+ n->cdr = p->parsing_heredoc;
+ }
+ else {
+ p->all_heredocs = p->parsing_heredoc;
+ }
+ }
+ else {
+ node *n, *m;
+ m = p->heredocs_from_nextline;
+ while (m->cdr)
+ m = m->cdr;
+ n = p->all_heredocs;
+ mrb_assert(n != NULL);
+ if (n == p->parsing_heredoc) {
+ m->cdr = n;
+ p->all_heredocs = p->heredocs_from_nextline;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ }
+ else {
+ while (n->cdr != p->parsing_heredoc) {
+ n = n->cdr;
+ mrb_assert(n != NULL);
+ }
+ m->cdr = n->cdr;
+ n->cdr = p->heredocs_from_nextline;
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ }
+ }
+ p->heredocs_from_nextline = NULL;
+}
+
+static void
heredoc_end(parser_state *p)
{
p->parsing_heredoc = p->parsing_heredoc->cdr;
@@ -921,19 +974,22 @@ heredoc_end(parser_state *p)
p->lstate = EXPR_BEG;
p->cmd_start = TRUE;
end_strterm(p);
+ p->lex_strterm = p->lex_strterm_before_heredoc;
+ p->lex_strterm_before_heredoc = NULL;
p->heredoc_end_now = TRUE;
- } else {
+ }
+ else {
/* next heredoc */
p->lex_strterm->car = (node*)(intptr_t)parsing_heredoc_inf(p)->type;
}
}
#define is_strterm_type(p,str_func) ((int)(intptr_t)((p)->lex_strterm->car) & (str_func))
-// xxx -----------------------------
+/* xxx ----------------------------- */
%}
-%pure_parser
+%pure-parser
%parse-param {parser_state *p}
%lex-param {parser_state *p}
@@ -946,54 +1002,54 @@ heredoc_end(parser_state *p)
}
%token
- keyword_class
- keyword_module
- keyword_def
- keyword_undef
- keyword_begin
- keyword_rescue
- keyword_ensure
- keyword_end
- keyword_if
- keyword_unless
- keyword_then
- keyword_elsif
- keyword_else
- keyword_case
- keyword_when
- keyword_while
- keyword_until
- keyword_for
- keyword_break
- keyword_next
- keyword_redo
- keyword_retry
- keyword_in
- keyword_do
- keyword_do_cond
- keyword_do_block
- keyword_do_LAMBDA
- keyword_return
- keyword_yield
- keyword_super
- keyword_self
- keyword_nil
- keyword_true
- keyword_false
- keyword_and
- keyword_or
- keyword_not
- modifier_if
- modifier_unless
- modifier_while
- modifier_until
- modifier_rescue
- keyword_alias
- keyword_BEGIN
- keyword_END
- keyword__LINE__
- keyword__FILE__
- keyword__ENCODING__
+ keyword_class
+ keyword_module
+ keyword_def
+ keyword_undef
+ keyword_begin
+ keyword_rescue
+ keyword_ensure
+ keyword_end
+ keyword_if
+ keyword_unless
+ keyword_then
+ keyword_elsif
+ keyword_else
+ keyword_case
+ keyword_when
+ keyword_while
+ keyword_until
+ keyword_for
+ keyword_break
+ keyword_next
+ keyword_redo
+ keyword_retry
+ keyword_in
+ keyword_do
+ keyword_do_cond
+ keyword_do_block
+ keyword_do_LAMBDA
+ keyword_return
+ keyword_yield
+ keyword_super
+ keyword_self
+ keyword_nil
+ keyword_true
+ keyword_false
+ keyword_and
+ keyword_or
+ keyword_not
+ modifier_if
+ modifier_unless
+ modifier_while
+ modifier_until
+ modifier_rescue
+ keyword_alias
+ keyword_BEGIN
+ keyword_END
+ keyword__LINE__
+ keyword__FILE__
+ keyword__ENCODING__
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
%token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
@@ -1052,10 +1108,11 @@ heredoc_end(parser_state *p)
%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
%token <nd> tHEREDOC_BEG /* <<, <<- */
-%token tHEREDOC_END tLITERAL_DELIM
+%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM
+%token <nd> tHD_STRING_PART tHD_STRING_MID
/*
- * precedence table
+ * precedence table
*/
%nonassoc tLOWEST
@@ -1095,2027 +1152,2082 @@ heredoc_end(parser_state *p)
%token tLAST_TOKEN
%%
-program : {
- p->lstate = EXPR_BEG;
- if (!p->locals) p->locals = cons(0,0);
- }
- top_compstmt
- {
- p->tree = new_scope(p, $2);
- }
- ;
-
-top_compstmt : top_stmts opt_terms
- {
- $$ = $1;
- }
- ;
-
-top_stmts : none
- {
- $$ = new_begin(p, 0);
- }
- | top_stmt
- {
- $$ = new_begin(p, $1);
- }
- | top_stmts terms top_stmt
- {
- $$ = push($1, newline_node($3));
- }
- | error top_stmt
- {
- $$ = new_begin(p, 0);
- }
- ;
-
-top_stmt : stmt
- | keyword_BEGIN
- {
- $<nd>$ = local_switch(p);
- }
- '{' top_compstmt '}'
- {
- yyerror(p, "BEGIN not supported");
- local_resume(p, $<nd>2);
- $$ = 0;
- }
- ;
-
-bodystmt : compstmt
- opt_rescue
- opt_else
- opt_ensure
- {
- if ($2) {
- $$ = new_rescue(p, $1, $2, $3);
- }
- else if ($3) {
- yywarn(p, "else without rescue is useless");
- $$ = push($1, $3);
- }
- else {
- $$ = $1;
- }
- if ($4) {
- if ($$) {
- $$ = new_ensure(p, $$, $4);
- }
- else {
- $$ = push($4, new_nil(p));
- }
- }
- }
- ;
-
-compstmt : stmts opt_terms
- {
- $$ = $1;
- }
- ;
-
-stmts : none
- {
- $$ = new_begin(p, 0);
- }
- | stmt
- {
- $$ = new_begin(p, $1);
- }
- | stmts terms stmt
- {
- $$ = push($1, newline_node($3));
- }
- | error stmt
- {
- $$ = new_begin(p, $2);
- }
- ;
-
-stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
- {
- $$ = new_alias(p, $2, $4);
- }
- | keyword_undef undef_list
- {
- $$ = $2;
- }
- | stmt modifier_if expr_value
- {
- $$ = new_if(p, cond($3), $1, 0);
- }
- | stmt modifier_unless expr_value
- {
- $$ = new_unless(p, cond($3), $1, 0);
- }
- | stmt modifier_while expr_value
- {
- $$ = new_while(p, cond($3), $1);
- }
- | stmt modifier_until expr_value
- {
- $$ = new_until(p, cond($3), $1);
- }
- | stmt modifier_rescue stmt
- {
- $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0);
- }
- | keyword_END '{' compstmt '}'
- {
- yyerror(p, "END not suported");
- $$ = new_postexe(p, $3);
- }
- | command_asgn
- | mlhs '=' command_call
- {
- $$ = new_masgn(p, $1, $3);
- }
- | var_lhs tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, $1, $2, $3);
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6);
- }
- | primary_value '.' tIDENTIFIER tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value '.' tCONSTANT tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call
- {
- yyerror(p, "constant re-assignment");
- $$ = 0;
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | backref tOP_ASGN command_call
- {
- backref_error(p, $1);
- $$ = new_begin(p, 0);
- }
- | lhs '=' mrhs
- {
- $$ = new_asgn(p, $1, new_array(p, $3));
- }
- | mlhs '=' arg_value
- {
- $$ = new_masgn(p, $1, $3);
- }
- | mlhs '=' mrhs
- {
- $$ = new_masgn(p, $1, new_array(p, $3));
- }
- | expr
- ;
-
-command_asgn : lhs '=' command_call
- {
- $$ = new_asgn(p, $1, $3);
- }
- | lhs '=' command_asgn
- {
- $$ = new_asgn(p, $1, $3);
- }
- ;
-
-
-expr : command_call
- | expr keyword_and expr
- {
- $$ = new_and(p, $1, $3);
- }
- | expr keyword_or expr
- {
- $$ = new_or(p, $1, $3);
- }
- | keyword_not opt_nl expr
- {
- $$ = call_uni_op(p, cond($3), "!");
- }
- | '!' command_call
- {
- $$ = call_uni_op(p, cond($2), "!");
- }
- | arg
- ;
-
-expr_value : expr
- {
- if (!$1) $$ = new_nil(p);
- else $$ = $1;
- }
- ;
-
-command_call : command
- | block_command
- ;
-
-block_command : block_call
- | block_call dot_or_colon operation2 command_args
- ;
-
-cmd_brace_block : tLBRACE_ARG
- {
- local_nest(p);
- }
- opt_block_param
- compstmt
- '}'
- {
- $$ = new_block(p, $3, $4);
- local_unnest(p);
- }
- ;
-
-command : operation command_args %prec tLOWEST
- {
- $$ = new_fcall(p, $1, $2);
- }
- | operation command_args cmd_brace_block
- {
- args_with_block(p, $2, $3);
- $$ = new_fcall(p, $1, $2);
- }
- | primary_value '.' operation2 command_args %prec tLOWEST
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value '.' operation2 command_args cmd_brace_block
- {
- args_with_block(p, $4, $5);
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 command_args %prec tLOWEST
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 command_args cmd_brace_block
- {
- args_with_block(p, $4, $5);
- $$ = new_call(p, $1, $3, $4);
- }
- | keyword_super command_args
- {
- $$ = new_super(p, $2);
- }
- | keyword_yield command_args
- {
- $$ = new_yield(p, $2);
- }
- | keyword_return call_args
- {
- $$ = new_return(p, ret_args(p, $2));
- }
- | keyword_break call_args
- {
- $$ = new_break(p, ret_args(p, $2));
- }
- | keyword_next call_args
- {
- $$ = new_next(p, ret_args(p, $2));
- }
- ;
-
-mlhs : mlhs_basic
- {
- $$ = $1;
- }
- | tLPAREN mlhs_inner rparen
- {
- $$ = $2;
- }
- ;
-
-mlhs_inner : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- $$ = list1($2);
- }
- ;
-
-mlhs_basic : mlhs_list
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item
- {
- $$ = list1(push($1,$2));
- }
- | mlhs_list tSTAR mlhs_node
- {
- $$ = list2($1, $3);
- }
- | mlhs_list tSTAR mlhs_node ',' mlhs_post
- {
- $$ = list3($1, $3, $5);
- }
- | mlhs_list tSTAR
- {
- $$ = list2($1, new_nil(p));
- }
- | mlhs_list tSTAR ',' mlhs_post
- {
- $$ = list3($1, new_nil(p), $4);
- }
- | tSTAR mlhs_node
- {
- $$ = list2(0, $2);
- }
- | tSTAR mlhs_node ',' mlhs_post
- {
- $$ = list3(0, $2, $4);
- }
- | tSTAR
- {
- $$ = list2(0, new_nil(p));
- }
- | tSTAR ',' mlhs_post
- {
- $$ = list3(0, new_nil(p), $3);
- }
- ;
-
-mlhs_item : mlhs_node
- | tLPAREN mlhs_inner rparen
- {
- $$ = $2;
- }
- ;
-
-mlhs_list : mlhs_item ','
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item ','
- {
- $$ = push($1, $2);
- }
- ;
-
-mlhs_post : mlhs_item
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item
- {
- $$ = push($1, $2);
- }
- ;
-
-mlhs_node : variable
- {
- assignable(p, $1);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern2("[]",2), $3);
- }
- | primary_value '.' tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' tCONSTANT
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon3(p, $2);
- }
- | backref
- {
- backref_error(p, $1);
- $$ = 0;
- }
- ;
-
-lhs : variable
- {
- assignable(p, $1);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern2("[]",2), $3);
- }
- | primary_value '.' tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' tCONSTANT
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon3(p, $2);
- }
- | backref
- {
- backref_error(p, $1);
- $$ = 0;
- }
- ;
-
-cname : tIDENTIFIER
- {
- yyerror(p, "class/module name must be CONSTANT");
- }
- | tCONSTANT
- ;
-
-cpath : tCOLON3 cname
- {
- $$ = cons((node*)1, nsym($2));
- }
- | cname
- {
- $$ = cons((node*)0, nsym($1));
- }
- | primary_value tCOLON2 cname
- {
- $$ = cons($1, nsym($3));
- }
- ;
-
-fname : tIDENTIFIER
- | tCONSTANT
- | tFID
- | op
- {
- p->lstate = EXPR_ENDFN;
- $$ = $1;
- }
- | reswords
- {
- p->lstate = EXPR_ENDFN;
- $$ = $<id>1;
- }
- ;
-
-fsym : fname
- | basic_symbol
- ;
-
-undef_list : fsym
- {
- $$ = new_undef(p, $1);
- }
- | undef_list ',' {p->lstate = EXPR_FNAME;} fsym
- {
- $$ = push($1, nsym($4));
- }
- ;
-
-op : '|' { $$ = intern_c('|'); }
- | '^' { $$ = intern_c('^'); }
- | '&' { $$ = intern_c('&'); }
- | tCMP { $$ = intern2("<=>",3); }
- | tEQ { $$ = intern2("==",2); }
- | tEQQ { $$ = intern2("===",3); }
- | tMATCH { $$ = intern2("=~",2); }
- | tNMATCH { $$ = intern2("!~",2); }
- | '>' { $$ = intern_c('>'); }
- | tGEQ { $$ = intern2(">=",2); }
- | '<' { $$ = intern_c('<'); }
- | tLEQ { $$ = intern2("<=",2); }
- | tNEQ { $$ = intern2("!=",2); }
- | tLSHFT { $$ = intern2("<<",2); }
- | tRSHFT { $$ = intern2(">>",2); }
- | '+' { $$ = intern_c('+'); }
- | '-' { $$ = intern_c('-'); }
- | '*' { $$ = intern_c('*'); }
- | tSTAR { $$ = intern_c('*'); }
- | '/' { $$ = intern_c('/'); }
- | '%' { $$ = intern_c('%'); }
- | tPOW { $$ = intern2("**",2); }
- | '!' { $$ = intern_c('!'); }
- | '~' { $$ = intern_c('~'); }
- | tUPLUS { $$ = intern2("+@",2); }
- | tUMINUS { $$ = intern2("-@",2); }
- | tAREF { $$ = intern2("[]",2); }
- | tASET { $$ = intern2("[]=",3); }
- | '`' { $$ = intern_c('`'); }
- ;
-
-reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
- | keyword_BEGIN | keyword_END
- | keyword_alias | keyword_and | keyword_begin
- | keyword_break | keyword_case | keyword_class | keyword_def
- | keyword_do | keyword_else | keyword_elsif
- | keyword_end | keyword_ensure | keyword_false
- | keyword_for | keyword_in | keyword_module | keyword_next
- | keyword_nil | keyword_not | keyword_or | keyword_redo
- | keyword_rescue | keyword_retry | keyword_return | keyword_self
- | keyword_super | keyword_then | keyword_true | keyword_undef
- | keyword_when | keyword_yield | keyword_if | keyword_unless
- | keyword_while | keyword_until
- ;
-
-arg : lhs '=' arg
- {
- $$ = new_asgn(p, $1, $3);
- }
- | lhs '=' arg modifier_rescue arg
- {
- $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
- }
- | var_lhs tOP_ASGN arg
- {
- $$ = new_op_asgn(p, $1, $2, $3);
- }
- | var_lhs tOP_ASGN arg modifier_rescue arg
- {
- $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6);
- }
- | primary_value '.' tIDENTIFIER tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value '.' tCONSTANT tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN arg
- {
- yyerror(p, "constant re-assignment");
- $$ = new_begin(p, 0);
- }
- | tCOLON3 tCONSTANT tOP_ASGN arg
- {
- yyerror(p, "constant re-assignment");
- $$ = new_begin(p, 0);
- }
- | backref tOP_ASGN arg
- {
- backref_error(p, $1);
- $$ = new_begin(p, 0);
- }
- | arg tDOT2 arg
- {
- $$ = new_dot2(p, $1, $3);
- }
- | arg tDOT3 arg
- {
- $$ = new_dot3(p, $1, $3);
- }
- | arg '+' arg
- {
- $$ = call_bin_op(p, $1, "+", $3);
- }
- | arg '-' arg
- {
- $$ = call_bin_op(p, $1, "-", $3);
- }
- | arg '*' arg
- {
- $$ = call_bin_op(p, $1, "*", $3);
- }
- | arg '/' arg
- {
- $$ = call_bin_op(p, $1, "/", $3);
- }
- | arg '%' arg
- {
- $$ = call_bin_op(p, $1, "%", $3);
- }
- | arg tPOW arg
- {
- $$ = call_bin_op(p, $1, "**", $3);
- }
- | tUMINUS_NUM tINTEGER tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
- }
- | tUMINUS_NUM tFLOAT tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
- }
- | tUPLUS arg
- {
- $$ = call_uni_op(p, $2, "+@");
- }
- | tUMINUS arg
- {
- $$ = call_uni_op(p, $2, "-@");
- }
- | arg '|' arg
- {
- $$ = call_bin_op(p, $1, "|", $3);
- }
- | arg '^' arg
- {
- $$ = call_bin_op(p, $1, "^", $3);
- }
- | arg '&' arg
- {
- $$ = call_bin_op(p, $1, "&", $3);
- }
- | arg tCMP arg
- {
- $$ = call_bin_op(p, $1, "<=>", $3);
- }
- | arg '>' arg
- {
- $$ = call_bin_op(p, $1, ">", $3);
- }
- | arg tGEQ arg
- {
- $$ = call_bin_op(p, $1, ">=", $3);
- }
- | arg '<' arg
- {
- $$ = call_bin_op(p, $1, "<", $3);
- }
- | arg tLEQ arg
- {
- $$ = call_bin_op(p, $1, "<=", $3);
- }
- | arg tEQ arg
- {
- $$ = call_bin_op(p, $1, "==", $3);
- }
- | arg tEQQ arg
- {
- $$ = call_bin_op(p, $1, "===", $3);
- }
- | arg tNEQ arg
- {
- $$ = call_bin_op(p, $1, "!=", $3);
- }
- | arg tMATCH arg
- {
- $$ = call_bin_op(p, $1, "=~", $3);
- }
- | arg tNMATCH arg
- {
- $$ = call_bin_op(p, $1, "!~", $3);
- }
- | '!' arg
- {
- $$ = call_uni_op(p, cond($2), "!");
- }
- | '~' arg
- {
- $$ = call_uni_op(p, cond($2), "~");
- }
- | arg tLSHFT arg
- {
- $$ = call_bin_op(p, $1, "<<", $3);
- }
- | arg tRSHFT arg
- {
- $$ = call_bin_op(p, $1, ">>", $3);
- }
- | arg tANDOP arg
- {
- $$ = new_and(p, $1, $3);
- }
- | arg tOROP arg
- {
- $$ = new_or(p, $1, $3);
- }
- | arg '?' arg opt_nl ':' arg
- {
- $$ = new_if(p, cond($1), $3, $6);
- }
- | primary
- {
- $$ = $1;
- }
- ;
-
-arg_value : arg
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- ;
-
-aref_args : none
- | args trailer
- {
- $$ = $1;
- }
- | args ',' assocs trailer
- {
- $$ = push($1, new_hash(p, $3));
- }
- | assocs trailer
- {
- $$ = cons(new_hash(p, $1), 0);
- }
- ;
-
-paren_args : '(' opt_call_args rparen
- {
- $$ = $2;
- }
- ;
-
-opt_paren_args : none
- | paren_args
- ;
-
-opt_call_args : none
- | call_args
- | args ','
- {
- $$ = cons($1,0);
- }
- | args ',' assocs ','
- {
- $$ = cons(push($1, new_hash(p, $3)), 0);
- }
- | assocs ','
- {
- $$ = cons(list1(new_hash(p, $1)), 0);
- }
- ;
-
-call_args : command
- {
- $$ = cons(list1($1), 0);
- }
- | args opt_block_arg
- {
- $$ = cons($1, $2);
- }
- | assocs opt_block_arg
- {
- $$ = cons(list1(new_hash(p, $1)), $2);
- }
- | args ',' assocs opt_block_arg
- {
- $$ = cons(push($1, new_hash(p, $3)), $4);
- }
- | block_arg
- {
- $$ = cons(0, $1);
- }
- ;
-
-command_args : {
- $<stack>$ = p->cmdarg_stack;
- CMDARG_PUSH(1);
- }
- call_args
- {
- p->cmdarg_stack = $<stack>1;
- $$ = $2;
- }
- ;
-
-block_arg : tAMPER arg_value
- {
- $$ = new_block_arg(p, $2);
- }
- ;
-
-opt_block_arg : ',' block_arg
- {
- $$ = $2;
- }
- | none
- {
- $$ = 0;
- }
- ;
-
-args : arg_value
- {
- $$ = cons($1, 0);
- }
- | tSTAR arg_value
- {
- $$ = cons(new_splat(p, $2), 0);
- }
- | args ',' arg_value
- {
- $$ = push($1, $3);
- }
- | args ',' tSTAR arg_value
- {
- $$ = push($1, new_splat(p, $4));
- }
- ;
-
-mrhs : args ',' arg_value
- {
- $$ = push($1, $3);
- }
- | args ',' tSTAR arg_value
- {
- $$ = push($1, new_splat(p, $4));
- }
- | tSTAR arg_value
- {
- $$ = list1(new_splat(p, $2));
- }
- ;
-
-primary : literal
- | string
- | xstring
- | regexp
- | heredoc
- | var_ref
- | backref
- | tFID
- {
- $$ = new_fcall(p, $1, 0);
- }
- | keyword_begin
- {
- $<stack>1 = p->cmdarg_stack;
- p->cmdarg_stack = 0;
- }
- bodystmt
- keyword_end
- {
- p->cmdarg_stack = $<stack>1;
- $$ = $3;
- }
- | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen
- {
- $$ = $2;
- }
- | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
- {
- $$ = 0;
- }
- | tLPAREN compstmt ')'
- {
- $$ = $2;
- }
- | primary_value tCOLON2 tCONSTANT
- {
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- $$ = new_colon3(p, $2);
- }
- | tLBRACK aref_args ']'
- {
- $$ = new_array(p, $2);
- }
- | tLBRACE assoc_list '}'
- {
- $$ = new_hash(p, $2);
- }
- | keyword_return
- {
- $$ = new_return(p, 0);
- }
- | keyword_yield '(' call_args rparen
- {
- $$ = new_yield(p, $3);
- }
- | keyword_yield '(' rparen
- {
- $$ = new_yield(p, 0);
- }
- | keyword_yield
- {
- $$ = new_yield(p, 0);
- }
- | keyword_not '(' expr rparen
- {
- $$ = call_uni_op(p, cond($3), "!");
- }
- | keyword_not '(' rparen
- {
- $$ = call_uni_op(p, new_nil(p), "!");
- }
- | operation brace_block
- {
- $$ = new_fcall(p, $1, cons(0, $2));
- }
- | method_call
- | method_call brace_block
- {
- call_with_block(p, $1, $2);
- $$ = $1;
- }
- | tLAMBDA
- {
- local_nest(p);
- $<num>$ = p->lpar_beg;
- p->lpar_beg = ++p->paren_nest;
- }
- f_larglist
- lambda_body
- {
- p->lpar_beg = $<num>2;
- $$ = new_lambda(p, $3, $4);
- local_unnest(p);
- }
- | keyword_if expr_value then
- compstmt
- if_tail
- keyword_end
- {
- $$ = new_if(p, cond($2), $4, $5);
- }
- | keyword_unless expr_value then
- compstmt
- opt_else
- keyword_end
- {
- $$ = new_unless(p, cond($2), $4, $5);
- }
- | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_while(p, cond($3), $6);
- }
- | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_until(p, cond($3), $6);
- }
- | keyword_case expr_value opt_terms
- case_body
- keyword_end
- {
- $$ = new_case(p, $2, $4);
- }
- | keyword_case opt_terms case_body keyword_end
- {
- $$ = new_case(p, 0, $3);
- }
- | keyword_for for_var keyword_in
- {COND_PUSH(1);}
- expr_value do
- {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_for(p, $2, $5, $8);
- }
- | keyword_class cpath superclass
- {
- if (p->in_def || p->in_single)
- yyerror(p, "class definition in method body");
- $<nd>$ = local_switch(p);
- }
- bodystmt
- keyword_end
- {
- $$ = new_class(p, $2, $3, $5);
- local_resume(p, $<nd>4);
- }
- | keyword_class tLSHFT expr
- {
- $<num>$ = p->in_def;
- p->in_def = 0;
- }
- term
- {
- $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single);
- p->in_single = 0;
- }
- bodystmt
- keyword_end
- {
- $$ = new_sclass(p, $3, $7);
- local_resume(p, $<nd>6->car);
- p->in_def = $<num>4;
- p->in_single = (int)(intptr_t)$<nd>6->cdr;
- }
- | keyword_module cpath
- {
- if (p->in_def || p->in_single)
- yyerror(p, "module definition in method body");
- $<nd>$ = local_switch(p);
- }
- bodystmt
- keyword_end
- {
- $$ = new_module(p, $2, $4);
- local_resume(p, $<nd>3);
- }
- | keyword_def fname
- {
- p->in_def++;
- $<nd>$ = local_switch(p);
- }
- f_arglist
- bodystmt
- keyword_end
- {
- $$ = new_def(p, $2, $4, $5);
- local_resume(p, $<nd>3);
- p->in_def--;
- }
- | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname
- {
- p->in_single++;
- p->lstate = EXPR_ENDFN; /* force for args */
- $<nd>$ = local_switch(p);
- }
- f_arglist
- bodystmt
- keyword_end
- {
- $$ = new_sdef(p, $2, $5, $7, $8);
- local_resume(p, $<nd>6);
- p->in_single--;
- }
- | keyword_break
- {
- $$ = new_break(p, 0);
- }
- | keyword_next
- {
- $$ = new_next(p, 0);
- }
- | keyword_redo
- {
- $$ = new_redo(p);
- }
- | keyword_retry
- {
- $$ = new_retry(p);
- }
- ;
-
-primary_value : primary
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- ;
-
-then : term
- | keyword_then
- | term keyword_then
- ;
-
-do : term
- | keyword_do_cond
- ;
-
-if_tail : opt_else
- | keyword_elsif expr_value then
- compstmt
- if_tail
- {
- $$ = new_if(p, cond($2), $4, $5);
- }
- ;
-
-opt_else : none
- | keyword_else compstmt
- {
- $$ = $2;
- }
- ;
-
-for_var : lhs
- {
- $$ = list1(list1($1));
- }
- | mlhs
- ;
-
-f_marg : f_norm_arg
- {
- $$ = new_arg(p, $1);
- }
- | tLPAREN f_margs rparen
- {
- $$ = new_masgn(p, $2, 0);
- }
- ;
-
-f_marg_list : f_marg
- {
- $$ = list1($1);
- }
- | f_marg_list ',' f_marg
- {
- $$ = push($1, $3);
- }
- ;
-
-f_margs : f_marg_list
- {
- $$ = list3($1,0,0);
- }
- | f_marg_list ',' tSTAR f_norm_arg
- {
- $$ = list3($1, new_arg(p, $4), 0);
- }
- | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
- {
- $$ = list3($1, new_arg(p, $4), $6);
- }
- | f_marg_list ',' tSTAR
- {
- $$ = list3($1, (node*)-1, 0);
- }
- | f_marg_list ',' tSTAR ',' f_marg_list
- {
- $$ = list3($1, (node*)-1, $5);
- }
- | tSTAR f_norm_arg
- {
- $$ = list3(0, new_arg(p, $2), 0);
- }
- | tSTAR f_norm_arg ',' f_marg_list
- {
- $$ = list3(0, new_arg(p, $2), $4);
- }
- | tSTAR
- {
- $$ = list3(0, (node*)-1, 0);
- }
- | tSTAR ',' f_marg_list
- {
- $$ = list3(0, (node*)-1, $3);
- }
- ;
-
-block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, 0, $6);
- }
- | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, $7, $8);
- }
- | f_arg ',' f_block_optarg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, 0, $4);
- }
- | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, $5, $6);
- }
- | f_arg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, 0, $4);
- }
- | f_arg ','
- {
- $$ = new_args(p, $1, 0, 1, 0, 0);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, $5, $6);
- }
- | f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, 0, 0, $2);
- }
- | f_block_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, 0, $4);
- }
- | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, $5, $6);
- }
- | f_block_optarg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, 0, $2);
- }
- | f_block_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, $3, $4);
- }
- | f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, 0, $2);
- }
- | f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, $3, $4);
- }
- | f_block_arg
- {
- $$ = new_args(p, 0, 0, 0, 0, $1);
- }
- ;
-
-opt_block_param : none
- | block_param_def
- {
- p->cmd_start = TRUE;
- $$ = $1;
- }
- ;
-
-block_param_def : '|' opt_bv_decl '|'
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- | tOROP
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- | '|' block_param opt_bv_decl '|'
- {
- $$ = $2;
- }
- ;
-
-
-opt_bv_decl : opt_nl
- {
- $$ = 0;
- }
- | opt_nl ';' bv_decls opt_nl
- {
- $$ = 0;
- }
- ;
-
-bv_decls : bvar
- | bv_decls ',' bvar
- ;
-
-bvar : tIDENTIFIER
- {
- local_add_f(p, $1);
- new_bv(p, $1);
- }
- | f_bad_arg
- ;
-
-f_larglist : '(' f_args opt_bv_decl ')'
- {
- $$ = $2;
- }
- | f_args
- {
- $$ = $1;
- }
- ;
-
-lambda_body : tLAMBEG compstmt '}'
- {
- $$ = $2;
- }
- | keyword_do_LAMBDA compstmt keyword_end
- {
- $$ = $2;
- }
- ;
-
-do_block : keyword_do_block
- {
- local_nest(p);
- }
- opt_block_param
- compstmt
- keyword_end
- {
- $$ = new_block(p,$3,$4);
- local_unnest(p);
- }
- ;
-
-block_call : command do_block
- {
- if ($1->car == (node*)NODE_YIELD) {
- yyerror(p, "block given to yield");
- }
- else {
- call_with_block(p, $1, $2);
- }
- $$ = $1;
- }
- | block_call dot_or_colon operation2 opt_paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | block_call dot_or_colon operation2 opt_paren_args brace_block
- {
- $$ = new_call(p, $1, $3, $4);
- call_with_block(p, $$, $5);
- }
- | block_call dot_or_colon operation2 command_args do_block
- {
- $$ = new_call(p, $1, $3, $4);
- call_with_block(p, $$, $5);
- }
- ;
-
-method_call : operation paren_args
- {
- $$ = new_fcall(p, $1, $2);
- }
- | primary_value '.' operation2 opt_paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation3
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' paren_args
- {
- $$ = new_call(p, $1, intern2("call",4), $3);
- }
- | primary_value tCOLON2 paren_args
- {
- $$ = new_call(p, $1, intern2("call",4), $3);
- }
- | keyword_super paren_args
- {
- $$ = new_super(p, $2);
- }
- | keyword_super
- {
- $$ = new_zsuper(p);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern2("[]",2), $3);
- }
- ;
-
-brace_block : '{'
- {
- local_nest(p);
- }
- opt_block_param
- compstmt '}'
- {
- $$ = new_block(p,$3,$4);
- local_unnest(p);
- }
- | keyword_do
- {
- local_nest(p);
- }
- opt_block_param
- compstmt keyword_end
- {
- $$ = new_block(p,$3,$4);
- local_unnest(p);
- }
- ;
-
-case_body : keyword_when args then
- compstmt
- cases
- {
- $$ = cons(cons($2, $4), $5);
- }
- ;
-
-cases : opt_else
- {
- if ($1) {
- $$ = cons(cons(0, $1), 0);
- }
- else {
- $$ = 0;
- }
- }
- | case_body
- ;
-
-opt_rescue : keyword_rescue exc_list exc_var then
- compstmt
- opt_rescue
- {
- $$ = list1(list3($2, $3, $5));
- if ($6) $$ = append($$, $6);
- }
- | none
- ;
-
-exc_list : arg_value
- {
- $$ = list1($1);
- }
- | mrhs
- | none
- ;
-
-exc_var : tASSOC lhs
- {
- $$ = $2;
- }
- | none
- ;
-
-opt_ensure : keyword_ensure compstmt
- {
- $$ = $2;
- }
- | none
- ;
-
-literal : numeric
- | symbol
- | words
- | symbols
- ;
-
-string : tCHAR
- | tSTRING
- | tSTRING_BEG tSTRING
- {
- $$ = $2;
- }
- | tSTRING_BEG string_rep tSTRING
- {
- $$ = new_dstr(p, push($2, $3));
- }
- ;
+program : {
+ p->lstate = EXPR_BEG;
+ if (!p->locals) p->locals = cons(0,0);
+ }
+ top_compstmt
+ {
+ p->tree = new_scope(p, $2);
+ }
+ ;
+
+top_compstmt : top_stmts opt_terms
+ {
+ $$ = $1;
+ }
+ ;
+
+top_stmts : none
+ {
+ $$ = new_begin(p, 0);
+ }
+ | top_stmt
+ {
+ $$ = new_begin(p, $1);
+ }
+ | top_stmts terms top_stmt
+ {
+ $$ = push($1, newline_node($3));
+ }
+ | error top_stmt
+ {
+ $$ = new_begin(p, 0);
+ }
+ ;
+
+top_stmt : stmt
+ | keyword_BEGIN
+ {
+ $<nd>$ = local_switch(p);
+ }
+ '{' top_compstmt '}'
+ {
+ yyerror(p, "BEGIN not supported");
+ local_resume(p, $<nd>2);
+ $$ = 0;
+ }
+ ;
+
+bodystmt : compstmt
+ opt_rescue
+ opt_else
+ opt_ensure
+ {
+ if ($2) {
+ $$ = new_rescue(p, $1, $2, $3);
+ }
+ else if ($3) {
+ yywarn(p, "else without rescue is useless");
+ $$ = push($1, $3);
+ }
+ else {
+ $$ = $1;
+ }
+ if ($4) {
+ if ($$) {
+ $$ = new_ensure(p, $$, $4);
+ }
+ else {
+ $$ = push($4, new_nil(p));
+ }
+ }
+ }
+ ;
+
+compstmt : stmts opt_terms
+ {
+ $$ = $1;
+ }
+ ;
+
+stmts : none
+ {
+ $$ = new_begin(p, 0);
+ }
+ | stmt
+ {
+ $$ = new_begin(p, $1);
+ }
+ | stmts terms stmt
+ {
+ $$ = push($1, newline_node($3));
+ }
+ | error stmt
+ {
+ $$ = new_begin(p, $2);
+ }
+ ;
+
+stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
+ {
+ $$ = new_alias(p, $2, $4);
+ }
+ | keyword_undef undef_list
+ {
+ $$ = $2;
+ }
+ | stmt modifier_if expr_value
+ {
+ $$ = new_if(p, cond($3), $1, 0);
+ }
+ | stmt modifier_unless expr_value
+ {
+ $$ = new_unless(p, cond($3), $1, 0);
+ }
+ | stmt modifier_while expr_value
+ {
+ $$ = new_while(p, cond($3), $1);
+ }
+ | stmt modifier_until expr_value
+ {
+ $$ = new_until(p, cond($3), $1);
+ }
+ | stmt modifier_rescue stmt
+ {
+ $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0);
+ }
+ | keyword_END '{' compstmt '}'
+ {
+ yyerror(p, "END not suported");
+ $$ = new_postexe(p, $3);
+ }
+ | command_asgn
+ | mlhs '=' command_call
+ {
+ $$ = new_masgn(p, $1, $3);
+ }
+ | var_lhs tOP_ASGN command_call
+ {
+ $$ = new_op_asgn(p, $1, $2, $3);
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN command_call
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6);
+ }
+ | primary_value '.' tIDENTIFIER tOP_ASGN command_call
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | primary_value '.' tCONSTANT tOP_ASGN command_call
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call
+ {
+ yyerror(p, "constant re-assignment");
+ $$ = 0;
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | backref tOP_ASGN command_call
+ {
+ backref_error(p, $1);
+ $$ = new_begin(p, 0);
+ }
+ | lhs '=' mrhs
+ {
+ $$ = new_asgn(p, $1, new_array(p, $3));
+ }
+ | mlhs '=' arg_value
+ {
+ $$ = new_masgn(p, $1, $3);
+ }
+ | mlhs '=' mrhs
+ {
+ $$ = new_masgn(p, $1, new_array(p, $3));
+ }
+ | expr
+ ;
+
+command_asgn : lhs '=' command_call
+ {
+ $$ = new_asgn(p, $1, $3);
+ }
+ | lhs '=' command_asgn
+ {
+ $$ = new_asgn(p, $1, $3);
+ }
+ ;
+
+
+expr : command_call
+ | expr keyword_and expr
+ {
+ $$ = new_and(p, $1, $3);
+ }
+ | expr keyword_or expr
+ {
+ $$ = new_or(p, $1, $3);
+ }
+ | keyword_not opt_nl expr
+ {
+ $$ = call_uni_op(p, cond($3), "!");
+ }
+ | '!' command_call
+ {
+ $$ = call_uni_op(p, cond($2), "!");
+ }
+ | arg
+ ;
+
+expr_value : expr
+ {
+ if (!$1) $$ = new_nil(p);
+ else $$ = $1;
+ }
+ ;
+
+command_call : command
+ | block_command
+ ;
+
+block_command : block_call
+ | block_call dot_or_colon operation2 command_args
+ ;
+
+cmd_brace_block : tLBRACE_ARG
+ {
+ local_nest(p);
+ }
+ opt_block_param
+ compstmt
+ '}'
+ {
+ $$ = new_block(p, $3, $4);
+ local_unnest(p);
+ }
+ ;
+
+command : operation command_args %prec tLOWEST
+ {
+ $$ = new_fcall(p, $1, $2);
+ }
+ | operation command_args cmd_brace_block
+ {
+ args_with_block(p, $2, $3);
+ $$ = new_fcall(p, $1, $2);
+ }
+ | primary_value '.' operation2 command_args %prec tLOWEST
+ {
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | primary_value '.' operation2 command_args cmd_brace_block
+ {
+ args_with_block(p, $4, $5);
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | primary_value tCOLON2 operation2 command_args %prec tLOWEST
+ {
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | primary_value tCOLON2 operation2 command_args cmd_brace_block
+ {
+ args_with_block(p, $4, $5);
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | keyword_super command_args
+ {
+ $$ = new_super(p, $2);
+ }
+ | keyword_yield command_args
+ {
+ $$ = new_yield(p, $2);
+ }
+ | keyword_return call_args
+ {
+ $$ = new_return(p, ret_args(p, $2));
+ }
+ | keyword_break call_args
+ {
+ $$ = new_break(p, ret_args(p, $2));
+ }
+ | keyword_next call_args
+ {
+ $$ = new_next(p, ret_args(p, $2));
+ }
+ ;
+
+mlhs : mlhs_basic
+ {
+ $$ = $1;
+ }
+ | tLPAREN mlhs_inner rparen
+ {
+ $$ = $2;
+ }
+ ;
+
+mlhs_inner : mlhs_basic
+ | tLPAREN mlhs_inner rparen
+ {
+ $$ = list1($2);
+ }
+ ;
+
+mlhs_basic : mlhs_list
+ {
+ $$ = list1($1);
+ }
+ | mlhs_list mlhs_item
+ {
+ $$ = list1(push($1,$2));
+ }
+ | mlhs_list tSTAR mlhs_node
+ {
+ $$ = list2($1, $3);
+ }
+ | mlhs_list tSTAR mlhs_node ',' mlhs_post
+ {
+ $$ = list3($1, $3, $5);
+ }
+ | mlhs_list tSTAR
+ {
+ $$ = list2($1, new_nil(p));
+ }
+ | mlhs_list tSTAR ',' mlhs_post
+ {
+ $$ = list3($1, new_nil(p), $4);
+ }
+ | tSTAR mlhs_node
+ {
+ $$ = list2(0, $2);
+ }
+ | tSTAR mlhs_node ',' mlhs_post
+ {
+ $$ = list3(0, $2, $4);
+ }
+ | tSTAR
+ {
+ $$ = list2(0, new_nil(p));
+ }
+ | tSTAR ',' mlhs_post
+ {
+ $$ = list3(0, new_nil(p), $3);
+ }
+ ;
+
+mlhs_item : mlhs_node
+ | tLPAREN mlhs_inner rparen
+ {
+ $$ = $2;
+ }
+ ;
+
+mlhs_list : mlhs_item ','
+ {
+ $$ = list1($1);
+ }
+ | mlhs_list mlhs_item ','
+ {
+ $$ = push($1, $2);
+ }
+ ;
+
+mlhs_post : mlhs_item
+ {
+ $$ = list1($1);
+ }
+ | mlhs_list mlhs_item
+ {
+ $$ = push($1, $2);
+ }
+ ;
+
+mlhs_node : variable
+ {
+ assignable(p, $1);
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ $$ = new_call(p, $1, intern("[]",2), $3);
+ }
+ | primary_value '.' tIDENTIFIER
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value '.' tCONSTANT
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "dynamic constant assignment");
+ $$ = new_colon2(p, $1, $3);
+ }
+ | tCOLON3 tCONSTANT
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "dynamic constant assignment");
+ $$ = new_colon3(p, $2);
+ }
+ | backref
+ {
+ backref_error(p, $1);
+ $$ = 0;
+ }
+ ;
+
+lhs : variable
+ {
+ assignable(p, $1);
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ $$ = new_call(p, $1, intern("[]",2), $3);
+ }
+ | primary_value '.' tIDENTIFIER
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value '.' tCONSTANT
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "dynamic constant assignment");
+ $$ = new_colon2(p, $1, $3);
+ }
+ | tCOLON3 tCONSTANT
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "dynamic constant assignment");
+ $$ = new_colon3(p, $2);
+ }
+ | backref
+ {
+ backref_error(p, $1);
+ $$ = 0;
+ }
+ ;
+
+cname : tIDENTIFIER
+ {
+ yyerror(p, "class/module name must be CONSTANT");
+ }
+ | tCONSTANT
+ ;
+
+cpath : tCOLON3 cname
+ {
+ $$ = cons((node*)1, nsym($2));
+ }
+ | cname
+ {
+ $$ = cons((node*)0, nsym($1));
+ }
+ | primary_value tCOLON2 cname
+ {
+ $$ = cons($1, nsym($3));
+ }
+ ;
+
+fname : tIDENTIFIER
+ | tCONSTANT
+ | tFID
+ | op
+ {
+ p->lstate = EXPR_ENDFN;
+ $$ = $1;
+ }
+ | reswords
+ {
+ p->lstate = EXPR_ENDFN;
+ $$ = $<id>1;
+ }
+ ;
+
+fsym : fname
+ | basic_symbol
+ ;
+
+undef_list : fsym
+ {
+ $$ = new_undef(p, $1);
+ }
+ | undef_list ',' {p->lstate = EXPR_FNAME;} fsym
+ {
+ $$ = push($1, nsym($4));
+ }
+ ;
+
+op : '|' { $$ = intern_c('|'); }
+ | '^' { $$ = intern_c('^'); }
+ | '&' { $$ = intern_c('&'); }
+ | tCMP { $$ = intern("<=>",3); }
+ | tEQ { $$ = intern("==",2); }
+ | tEQQ { $$ = intern("===",3); }
+ | tMATCH { $$ = intern("=~",2); }
+ | tNMATCH { $$ = intern("!~",2); }
+ | '>' { $$ = intern_c('>'); }
+ | tGEQ { $$ = intern(">=",2); }
+ | '<' { $$ = intern_c('<'); }
+ | tLEQ { $$ = intern("<=",2); }
+ | tNEQ { $$ = intern("!=",2); }
+ | tLSHFT { $$ = intern("<<",2); }
+ | tRSHFT { $$ = intern(">>",2); }
+ | '+' { $$ = intern_c('+'); }
+ | '-' { $$ = intern_c('-'); }
+ | '*' { $$ = intern_c('*'); }
+ | tSTAR { $$ = intern_c('*'); }
+ | '/' { $$ = intern_c('/'); }
+ | '%' { $$ = intern_c('%'); }
+ | tPOW { $$ = intern("**",2); }
+ | '!' { $$ = intern_c('!'); }
+ | '~' { $$ = intern_c('~'); }
+ | tUPLUS { $$ = intern("+@",2); }
+ | tUMINUS { $$ = intern("-@",2); }
+ | tAREF { $$ = intern("[]",2); }
+ | tASET { $$ = intern("[]=",3); }
+ | '`' { $$ = intern_c('`'); }
+ ;
+
+reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
+ | keyword_BEGIN | keyword_END
+ | keyword_alias | keyword_and | keyword_begin
+ | keyword_break | keyword_case | keyword_class | keyword_def
+ | keyword_do | keyword_else | keyword_elsif
+ | keyword_end | keyword_ensure | keyword_false
+ | keyword_for | keyword_in | keyword_module | keyword_next
+ | keyword_nil | keyword_not | keyword_or | keyword_redo
+ | keyword_rescue | keyword_retry | keyword_return | keyword_self
+ | keyword_super | keyword_then | keyword_true | keyword_undef
+ | keyword_when | keyword_yield | keyword_if | keyword_unless
+ | keyword_while | keyword_until
+ ;
+
+arg : lhs '=' arg
+ {
+ $$ = new_asgn(p, $1, $3);
+ }
+ | lhs '=' arg modifier_rescue arg
+ {
+ $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
+ }
+ | var_lhs tOP_ASGN arg
+ {
+ $$ = new_op_asgn(p, $1, $2, $3);
+ }
+ | var_lhs tOP_ASGN arg modifier_rescue arg
+ {
+ $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN arg
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6);
+ }
+ | primary_value '.' tIDENTIFIER tOP_ASGN arg
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | primary_value '.' tCONSTANT tOP_ASGN arg
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg
+ {
+ $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN arg
+ {
+ yyerror(p, "constant re-assignment");
+ $$ = new_begin(p, 0);
+ }
+ | tCOLON3 tCONSTANT tOP_ASGN arg
+ {
+ yyerror(p, "constant re-assignment");
+ $$ = new_begin(p, 0);
+ }
+ | backref tOP_ASGN arg
+ {
+ backref_error(p, $1);
+ $$ = new_begin(p, 0);
+ }
+ | arg tDOT2 arg
+ {
+ $$ = new_dot2(p, $1, $3);
+ }
+ | arg tDOT3 arg
+ {
+ $$ = new_dot3(p, $1, $3);
+ }
+ | arg '+' arg
+ {
+ $$ = call_bin_op(p, $1, "+", $3);
+ }
+ | arg '-' arg
+ {
+ $$ = call_bin_op(p, $1, "-", $3);
+ }
+ | arg '*' arg
+ {
+ $$ = call_bin_op(p, $1, "*", $3);
+ }
+ | arg '/' arg
+ {
+ $$ = call_bin_op(p, $1, "/", $3);
+ }
+ | arg '%' arg
+ {
+ $$ = call_bin_op(p, $1, "%", $3);
+ }
+ | arg tPOW arg
+ {
+ $$ = call_bin_op(p, $1, "**", $3);
+ }
+ | tUMINUS_NUM tINTEGER tPOW arg
+ {
+ $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
+ }
+ | tUMINUS_NUM tFLOAT tPOW arg
+ {
+ $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
+ }
+ | tUPLUS arg
+ {
+ $$ = call_uni_op(p, $2, "+@");
+ }
+ | tUMINUS arg
+ {
+ $$ = call_uni_op(p, $2, "-@");
+ }
+ | arg '|' arg
+ {
+ $$ = call_bin_op(p, $1, "|", $3);
+ }
+ | arg '^' arg
+ {
+ $$ = call_bin_op(p, $1, "^", $3);
+ }
+ | arg '&' arg
+ {
+ $$ = call_bin_op(p, $1, "&", $3);
+ }
+ | arg tCMP arg
+ {
+ $$ = call_bin_op(p, $1, "<=>", $3);
+ }
+ | arg '>' arg
+ {
+ $$ = call_bin_op(p, $1, ">", $3);
+ }
+ | arg tGEQ arg
+ {
+ $$ = call_bin_op(p, $1, ">=", $3);
+ }
+ | arg '<' arg
+ {
+ $$ = call_bin_op(p, $1, "<", $3);
+ }
+ | arg tLEQ arg
+ {
+ $$ = call_bin_op(p, $1, "<=", $3);
+ }
+ | arg tEQ arg
+ {
+ $$ = call_bin_op(p, $1, "==", $3);
+ }
+ | arg tEQQ arg
+ {
+ $$ = call_bin_op(p, $1, "===", $3);
+ }
+ | arg tNEQ arg
+ {
+ $$ = call_bin_op(p, $1, "!=", $3);
+ }
+ | arg tMATCH arg
+ {
+ $$ = call_bin_op(p, $1, "=~", $3);
+ }
+ | arg tNMATCH arg
+ {
+ $$ = call_bin_op(p, $1, "!~", $3);
+ }
+ | '!' arg
+ {
+ $$ = call_uni_op(p, cond($2), "!");
+ }
+ | '~' arg
+ {
+ $$ = call_uni_op(p, cond($2), "~");
+ }
+ | arg tLSHFT arg
+ {
+ $$ = call_bin_op(p, $1, "<<", $3);
+ }
+ | arg tRSHFT arg
+ {
+ $$ = call_bin_op(p, $1, ">>", $3);
+ }
+ | arg tANDOP arg
+ {
+ $$ = new_and(p, $1, $3);
+ }
+ | arg tOROP arg
+ {
+ $$ = new_or(p, $1, $3);
+ }
+ | arg '?' arg opt_nl ':' arg
+ {
+ $$ = new_if(p, cond($1), $3, $6);
+ }
+ | primary
+ {
+ $$ = $1;
+ }
+ ;
+
+arg_value : arg
+ {
+ $$ = $1;
+ if (!$$) $$ = new_nil(p);
+ }
+ ;
+
+aref_args : none
+ | args trailer
+ {
+ $$ = $1;
+ }
+ | args ',' assocs trailer
+ {
+ $$ = push($1, new_hash(p, $3));
+ }
+ | assocs trailer
+ {
+ $$ = cons(new_hash(p, $1), 0);
+ }
+ ;
+
+paren_args : '(' opt_call_args rparen
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_paren_args : none
+ | paren_args
+ ;
+
+opt_call_args : none
+ | call_args
+ | args ','
+ {
+ $$ = cons($1,0);
+ }
+ | args ',' assocs ','
+ {
+ $$ = cons(push($1, new_hash(p, $3)), 0);
+ }
+ | assocs ','
+ {
+ $$ = cons(list1(new_hash(p, $1)), 0);
+ }
+ ;
+
+call_args : command
+ {
+ $$ = cons(list1($1), 0);
+ }
+ | args opt_block_arg
+ {
+ $$ = cons($1, $2);
+ }
+ | assocs opt_block_arg
+ {
+ $$ = cons(list1(new_hash(p, $1)), $2);
+ }
+ | args ',' assocs opt_block_arg
+ {
+ $$ = cons(push($1, new_hash(p, $3)), $4);
+ }
+ | block_arg
+ {
+ $$ = cons(0, $1);
+ }
+ ;
+
+command_args : {
+ $<stack>$ = p->cmdarg_stack;
+ CMDARG_PUSH(1);
+ }
+ call_args
+ {
+ p->cmdarg_stack = $<stack>1;
+ $$ = $2;
+ }
+ ;
+
+block_arg : tAMPER arg_value
+ {
+ $$ = new_block_arg(p, $2);
+ }
+ ;
+
+opt_block_arg : ',' block_arg
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ $$ = 0;
+ }
+ ;
+
+args : arg_value
+ {
+ $$ = cons($1, 0);
+ }
+ | tSTAR arg_value
+ {
+ $$ = cons(new_splat(p, $2), 0);
+ }
+ | args ',' arg_value
+ {
+ $$ = push($1, $3);
+ }
+ | args ',' tSTAR arg_value
+ {
+ $$ = push($1, new_splat(p, $4));
+ }
+ | args ',' heredoc_bodies arg_value
+ {
+ $$ = push($1, $4);
+ }
+ | args ',' heredoc_bodies tSTAR arg_value
+ {
+ $$ = push($1, new_splat(p, $5));
+ }
+ ;
+
+mrhs : args ',' arg_value
+ {
+ $$ = push($1, $3);
+ }
+ | args ',' tSTAR arg_value
+ {
+ $$ = push($1, new_splat(p, $4));
+ }
+ | tSTAR arg_value
+ {
+ $$ = list1(new_splat(p, $2));
+ }
+ ;
+
+primary : literal
+ | string
+ | xstring
+ | regexp
+ | heredoc
+ | var_ref
+ | backref
+ | tFID
+ {
+ $$ = new_fcall(p, $1, 0);
+ }
+ | keyword_begin
+ {
+ $<stack>1 = p->cmdarg_stack;
+ p->cmdarg_stack = 0;
+ }
+ bodystmt
+ keyword_end
+ {
+ p->cmdarg_stack = $<stack>1;
+ $$ = $3;
+ }
+ | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen
+ {
+ $$ = $2;
+ }
+ | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
+ {
+ $$ = 0;
+ }
+ | tLPAREN compstmt ')'
+ {
+ $$ = $2;
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ $$ = new_colon2(p, $1, $3);
+ }
+ | tCOLON3 tCONSTANT
+ {
+ $$ = new_colon3(p, $2);
+ }
+ | tLBRACK aref_args ']'
+ {
+ $$ = new_array(p, $2);
+ }
+ | tLBRACE assoc_list '}'
+ {
+ $$ = new_hash(p, $2);
+ }
+ | keyword_return
+ {
+ $$ = new_return(p, 0);
+ }
+ | keyword_yield '(' call_args rparen
+ {
+ $$ = new_yield(p, $3);
+ }
+ | keyword_yield '(' rparen
+ {
+ $$ = new_yield(p, 0);
+ }
+ | keyword_yield
+ {
+ $$ = new_yield(p, 0);
+ }
+ | keyword_not '(' expr rparen
+ {
+ $$ = call_uni_op(p, cond($3), "!");
+ }
+ | keyword_not '(' rparen
+ {
+ $$ = call_uni_op(p, new_nil(p), "!");
+ }
+ | operation brace_block
+ {
+ $$ = new_fcall(p, $1, cons(0, $2));
+ }
+ | method_call
+ | method_call brace_block
+ {
+ call_with_block(p, $1, $2);
+ $$ = $1;
+ }
+ | tLAMBDA
+ {
+ local_nest(p);
+ $<num>$ = p->lpar_beg;
+ p->lpar_beg = ++p->paren_nest;
+ }
+ f_larglist
+ lambda_body
+ {
+ p->lpar_beg = $<num>2;
+ $$ = new_lambda(p, $3, $4);
+ local_unnest(p);
+ }
+ | keyword_if expr_value then
+ compstmt
+ if_tail
+ keyword_end
+ {
+ $$ = new_if(p, cond($2), $4, $5);
+ }
+ | keyword_unless expr_value then
+ compstmt
+ opt_else
+ keyword_end
+ {
+ $$ = new_unless(p, cond($2), $4, $5);
+ }
+ | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
+ compstmt
+ keyword_end
+ {
+ $$ = new_while(p, cond($3), $6);
+ }
+ | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();}
+ compstmt
+ keyword_end
+ {
+ $$ = new_until(p, cond($3), $6);
+ }
+ | keyword_case expr_value opt_terms
+ case_body
+ keyword_end
+ {
+ $$ = new_case(p, $2, $4);
+ }
+ | keyword_case opt_terms case_body keyword_end
+ {
+ $$ = new_case(p, 0, $3);
+ }
+ | keyword_for for_var keyword_in
+ {COND_PUSH(1);}
+ expr_value do
+ {COND_POP();}
+ compstmt
+ keyword_end
+ {
+ $$ = new_for(p, $2, $5, $8);
+ }
+ | keyword_class
+ {
+ $<num>$ = p->lineno;
+ }
+ cpath superclass
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "class definition in method body");
+ $<nd>$ = local_switch(p);
+ }
+ bodystmt
+ keyword_end
+ {
+ $$ = new_class(p, $3, $4, $6);
+ SET_LINENO($$, $<num>2);
+ local_resume(p, $<nd>5);
+ }
+ | keyword_class
+ {
+ $<num>$ = p->lineno;
+ }
+ tLSHFT expr
+ {
+ $<num>$ = p->in_def;
+ p->in_def = 0;
+ }
+ term
+ {
+ $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single);
+ p->in_single = 0;
+ }
+ bodystmt
+ keyword_end
+ {
+ $$ = new_sclass(p, $4, $8);
+ SET_LINENO($$, $<num>2);
+ local_resume(p, $<nd>7->car);
+ p->in_def = $<num>5;
+ p->in_single = (int)(intptr_t)$<nd>7->cdr;
+ }
+ | keyword_module
+ {
+ $<num>$ = p->lineno;
+ }
+ cpath
+ {
+ if (p->in_def || p->in_single)
+ yyerror(p, "module definition in method body");
+ $<nd>$ = local_switch(p);
+ }
+ bodystmt
+ keyword_end
+ {
+ $$ = new_module(p, $3, $5);
+ SET_LINENO($$, $<num>2);
+ local_resume(p, $<nd>4);
+ }
+ | keyword_def fname
+ {
+ p->in_def++;
+ $<nd>$ = local_switch(p);
+ }
+ f_arglist
+ bodystmt
+ keyword_end
+ {
+ $$ = new_def(p, $2, $4, $5);
+ local_resume(p, $<nd>3);
+ p->in_def--;
+ }
+ | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname
+ {
+ p->in_single++;
+ p->lstate = EXPR_ENDFN; /* force for args */
+ $<nd>$ = local_switch(p);
+ }
+ f_arglist
+ bodystmt
+ keyword_end
+ {
+ $$ = new_sdef(p, $2, $5, $7, $8);
+ local_resume(p, $<nd>6);
+ p->in_single--;
+ }
+ | keyword_break
+ {
+ $$ = new_break(p, 0);
+ }
+ | keyword_next
+ {
+ $$ = new_next(p, 0);
+ }
+ | keyword_redo
+ {
+ $$ = new_redo(p);
+ }
+ | keyword_retry
+ {
+ $$ = new_retry(p);
+ }
+ ;
+
+primary_value : primary
+ {
+ $$ = $1;
+ if (!$$) $$ = new_nil(p);
+ }
+ ;
+
+then : term
+ | keyword_then
+ | term keyword_then
+ ;
+
+do : term
+ | keyword_do_cond
+ ;
+
+if_tail : opt_else
+ | keyword_elsif expr_value then
+ compstmt
+ if_tail
+ {
+ $$ = new_if(p, cond($2), $4, $5);
+ }
+ ;
+
+opt_else : none
+ | keyword_else compstmt
+ {
+ $$ = $2;
+ }
+ ;
+
+for_var : lhs
+ {
+ $$ = list1(list1($1));
+ }
+ | mlhs
+ ;
+
+f_marg : f_norm_arg
+ {
+ $$ = new_arg(p, $1);
+ }
+ | tLPAREN f_margs rparen
+ {
+ $$ = new_masgn(p, $2, 0);
+ }
+ ;
+
+f_marg_list : f_marg
+ {
+ $$ = list1($1);
+ }
+ | f_marg_list ',' f_marg
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+f_margs : f_marg_list
+ {
+ $$ = list3($1,0,0);
+ }
+ | f_marg_list ',' tSTAR f_norm_arg
+ {
+ $$ = list3($1, new_arg(p, $4), 0);
+ }
+ | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
+ {
+ $$ = list3($1, new_arg(p, $4), $6);
+ }
+ | f_marg_list ',' tSTAR
+ {
+ $$ = list3($1, (node*)-1, 0);
+ }
+ | f_marg_list ',' tSTAR ',' f_marg_list
+ {
+ $$ = list3($1, (node*)-1, $5);
+ }
+ | tSTAR f_norm_arg
+ {
+ $$ = list3(0, new_arg(p, $2), 0);
+ }
+ | tSTAR f_norm_arg ',' f_marg_list
+ {
+ $$ = list3(0, new_arg(p, $2), $4);
+ }
+ | tSTAR
+ {
+ $$ = list3(0, (node*)-1, 0);
+ }
+ | tSTAR ',' f_marg_list
+ {
+ $$ = list3(0, (node*)-1, $3);
+ }
+ ;
+
+block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, $5, 0, $6);
+ }
+ | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8);
+ }
+ | f_arg ',' f_block_optarg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, 0, 0, $4);
+ }
+ | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, 0, $5, $6);
+ }
+ | f_arg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, $3, 0, $4);
+ }
+ | f_arg ','
+ {
+ $$ = new_args(p, $1, 0, 1, 0, 0);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, $3, $5, $6);
+ }
+ | f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, 0, 0, $2);
+ }
+ | f_block_optarg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, $3, 0, $4);
+ }
+ | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, $3, $5, $6);
+ }
+ | f_block_optarg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, 0, 0, $2);
+ }
+ | f_block_optarg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, 0, $3, $4);
+ }
+ | f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, 0, $1, 0, $2);
+ }
+ | f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, 0, $1, $3, $4);
+ }
+ | f_block_arg
+ {
+ $$ = new_args(p, 0, 0, 0, 0, $1);
+ }
+ ;
+
+opt_block_param : none
+ | block_param_def
+ {
+ p->cmd_start = TRUE;
+ $$ = $1;
+ }
+ ;
+
+block_param_def : '|' opt_bv_decl '|'
+ {
+ local_add_f(p, 0);
+ $$ = 0;
+ }
+ | tOROP
+ {
+ local_add_f(p, 0);
+ $$ = 0;
+ }
+ | '|' block_param opt_bv_decl '|'
+ {
+ $$ = $2;
+ }
+ ;
+
+
+opt_bv_decl : opt_nl
+ {
+ $$ = 0;
+ }
+ | opt_nl ';' bv_decls opt_nl
+ {
+ $$ = 0;
+ }
+ ;
+
+bv_decls : bvar
+ | bv_decls ',' bvar
+ ;
+
+bvar : tIDENTIFIER
+ {
+ local_add_f(p, $1);
+ new_bv(p, $1);
+ }
+ | f_bad_arg
+ ;
+
+f_larglist : '(' f_args opt_bv_decl ')'
+ {
+ $$ = $2;
+ }
+ | f_args
+ {
+ $$ = $1;
+ }
+ ;
+
+lambda_body : tLAMBEG compstmt '}'
+ {
+ $$ = $2;
+ }
+ | keyword_do_LAMBDA compstmt keyword_end
+ {
+ $$ = $2;
+ }
+ ;
+
+do_block : keyword_do_block
+ {
+ local_nest(p);
+ }
+ opt_block_param
+ compstmt
+ keyword_end
+ {
+ $$ = new_block(p,$3,$4);
+ local_unnest(p);
+ }
+ ;
+
+block_call : command do_block
+ {
+ if ($1->car == (node*)NODE_YIELD) {
+ yyerror(p, "block given to yield");
+ }
+ else {
+ call_with_block(p, $1, $2);
+ }
+ $$ = $1;
+ }
+ | block_call dot_or_colon operation2 opt_paren_args
+ {
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | block_call dot_or_colon operation2 opt_paren_args brace_block
+ {
+ $$ = new_call(p, $1, $3, $4);
+ call_with_block(p, $$, $5);
+ }
+ | block_call dot_or_colon operation2 command_args do_block
+ {
+ $$ = new_call(p, $1, $3, $4);
+ call_with_block(p, $$, $5);
+ }
+ ;
+
+method_call : operation paren_args
+ {
+ $$ = new_fcall(p, $1, $2);
+ }
+ | primary_value '.' operation2 opt_paren_args
+ {
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | primary_value tCOLON2 operation2 paren_args
+ {
+ $$ = new_call(p, $1, $3, $4);
+ }
+ | primary_value tCOLON2 operation3
+ {
+ $$ = new_call(p, $1, $3, 0);
+ }
+ | primary_value '.' paren_args
+ {
+ $$ = new_call(p, $1, intern("call",4), $3);
+ }
+ | primary_value tCOLON2 paren_args
+ {
+ $$ = new_call(p, $1, intern("call",4), $3);
+ }
+ | keyword_super paren_args
+ {
+ $$ = new_super(p, $2);
+ }
+ | keyword_super
+ {
+ $$ = new_zsuper(p);
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ $$ = new_call(p, $1, intern("[]",2), $3);
+ }
+ ;
+
+brace_block : '{'
+ {
+ local_nest(p);
+ $<num>$ = p->lineno;
+ }
+ opt_block_param
+ compstmt '}'
+ {
+ $$ = new_block(p,$3,$4);
+ SET_LINENO($$, $<num>2);
+ local_unnest(p);
+ }
+ | keyword_do
+ {
+ local_nest(p);
+ $<num>$ = p->lineno;
+ }
+ opt_block_param
+ compstmt keyword_end
+ {
+ $$ = new_block(p,$3,$4);
+ SET_LINENO($$, $<num>2);
+ local_unnest(p);
+ }
+ ;
+
+case_body : keyword_when args then
+ compstmt
+ cases
+ {
+ $$ = cons(cons($2, $4), $5);
+ }
+ ;
+
+cases : opt_else
+ {
+ if ($1) {
+ $$ = cons(cons(0, $1), 0);
+ }
+ else {
+ $$ = 0;
+ }
+ }
+ | case_body
+ ;
+
+opt_rescue : keyword_rescue exc_list exc_var then
+ compstmt
+ opt_rescue
+ {
+ $$ = list1(list3($2, $3, $5));
+ if ($6) $$ = append($$, $6);
+ }
+ | none
+ ;
+
+exc_list : arg_value
+ {
+ $$ = list1($1);
+ }
+ | mrhs
+ | none
+ ;
+
+exc_var : tASSOC lhs
+ {
+ $$ = $2;
+ }
+ | none
+ ;
+
+opt_ensure : keyword_ensure compstmt
+ {
+ $$ = $2;
+ }
+ | none
+ ;
+
+literal : numeric
+ | symbol
+ | words
+ | symbols
+ ;
+
+string : tCHAR
+ | tSTRING
+ | tSTRING_BEG tSTRING
+ {
+ $$ = $2;
+ }
+ | tSTRING_BEG string_rep tSTRING
+ {
+ $$ = new_dstr(p, push($2, $3));
+ }
+ ;
string_rep : string_interp
- | string_rep string_interp
- {
- $$ = append($1, $2);
- }
- ;
-
-string_interp : tSTRING_MID
- {
- $$ = list1($1);
- }
- | tSTRING_PART
- {
- $<nd>$ = p->lex_strterm;
- p->lex_strterm = NULL;
- }
- compstmt
- '}'
- {
- p->lex_strterm = $<nd>2;
- $$ = list2($1, $3);
- }
- | tLITERAL_DELIM
- {
- $$ = list1(new_literal_delim(p));
- }
- ;
-
-xstring : tXSTRING_BEG tXSTRING
- {
- $$ = $2;
- }
- | tXSTRING_BEG string_rep tXSTRING
- {
- $$ = new_dxstr(p, push($2, $3));
- }
- ;
-
-regexp : tREGEXP_BEG tREGEXP
- {
- $$ = $2;
- }
- | tREGEXP_BEG string_rep tREGEXP
- {
- $$ = new_dregx(p, $2, $3);
- }
- ;
-
-heredoc : tHEREDOC_BEG
- ;
-
-opt_heredoc_bodies : none
- | heredoc_bodies
- ;
-
-heredoc_bodies : heredoc_body
- | heredoc_bodies heredoc_body
- ;
-
-heredoc_body : tHEREDOC_END
- {
- parsing_heredoc_inf(p)->doc = list1(new_str(p, "", 0));
- heredoc_end(p);
- }
- | string_rep tHEREDOC_END
- {
- parsing_heredoc_inf(p)->doc = $1;
- heredoc_end(p);
- }
- ;
-
-words : tWORDS_BEG tSTRING
- {
- $$ = new_words(p, list1($2));
- }
- | tWORDS_BEG string_rep tSTRING
- {
- $$ = new_words(p, push($2, $3));
- }
- ;
-
-
-symbol : basic_symbol
- {
- $$ = new_sym(p, $1);
- }
- | tSYMBEG tSTRING_BEG string_interp tSTRING
- {
- p->lstate = EXPR_END;
- $$ = new_dsym(p, push($3, $4));
- }
- ;
-
-basic_symbol : tSYMBEG sym
- {
- p->lstate = EXPR_END;
- $$ = $2;
- }
- ;
-
-sym : fname
- | tIVAR
- | tGVAR
- | tCVAR
- | tSTRING
- {
- $$ = new_strsym(p, $1);
- }
- | tSTRING_BEG tSTRING
- {
- $$ = new_strsym(p, $2);
- }
- ;
-
-symbols : tSYMBOLS_BEG tSTRING
- {
- $$ = new_symbols(p, list1($2));
- }
- | tSYMBOLS_BEG string_rep tSTRING
- {
- $$ = new_symbols(p, push($2, $3));
- }
- ;
-
-numeric : tINTEGER
- | tFLOAT
- | tUMINUS_NUM tINTEGER %prec tLOWEST
- {
- $$ = negate_lit(p, $2);
- }
- | tUMINUS_NUM tFLOAT %prec tLOWEST
- {
- $$ = negate_lit(p, $2);
- }
- ;
-
-variable : tIDENTIFIER
- {
- $$ = new_lvar(p, $1);
- }
- | tIVAR
- {
- $$ = new_ivar(p, $1);
- }
- | tGVAR
- {
- $$ = new_gvar(p, $1);
- }
- | tCVAR
- {
- $$ = new_cvar(p, $1);
- }
- | tCONSTANT
- {
- $$ = new_const(p, $1);
- }
- ;
-
-var_lhs : variable
- {
- assignable(p, $1);
- }
- ;
-
-var_ref : variable
- {
- $$ = var_reference(p, $1);
- }
- | keyword_nil
- {
- $$ = new_nil(p);
- }
- | keyword_self
- {
- $$ = new_self(p);
- }
- | keyword_true
- {
- $$ = new_true(p);
- }
- | keyword_false
- {
- $$ = new_false(p);
- }
- | keyword__FILE__
- {
- if (!p->filename) {
- p->filename = "(null)";
- }
- $$ = new_str(p, p->filename, strlen(p->filename));
- }
- | keyword__LINE__
- {
- char buf[16];
-
- snprintf(buf, sizeof(buf), "%d", p->lineno);
- $$ = new_int(p, buf, 10);
- }
- ;
-
-backref : tNTH_REF
- | tBACK_REF
- ;
-
-superclass : term
- {
- $$ = 0;
- }
- | '<'
- {
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- }
- expr_value term
- {
- $$ = $3;
- }
- | error term
- {
- yyerrok;
- $$ = 0;
- }
- ;
-
-f_arglist : '(' f_args rparen
- {
- $$ = $2;
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- }
- | f_args term
- {
- $$ = $1;
- }
- ;
-
-f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, 0, $6);
- }
- | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, $7, $8);
- }
- | f_arg ',' f_optarg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, 0, $4);
- }
- | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, $5, $6);
- }
- | f_arg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, 0, $4);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, $5, $6);
- }
- | f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, 0, 0, $2);
- }
- | f_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, 0, $4);
- }
- | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, $5, $6);
- }
- | f_optarg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, 0, $2);
- }
- | f_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, $3, $4);
- }
- | f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, 0, $2);
- }
- | f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, $3, $4);
- }
- | f_block_arg
- {
- $$ = new_args(p, 0, 0, 0, 0, $1);
- }
- | /* none */
- {
- local_add_f(p, 0);
- $$ = new_args(p, 0, 0, 0, 0, 0);
- }
- ;
-
-f_bad_arg : tCONSTANT
- {
- yyerror(p, "formal argument cannot be a constant");
- $$ = 0;
- }
- | tIVAR
- {
- yyerror(p, "formal argument cannot be an instance variable");
- $$ = 0;
- }
- | tGVAR
- {
- yyerror(p, "formal argument cannot be a global variable");
- $$ = 0;
- }
- | tCVAR
- {
- yyerror(p, "formal argument cannot be a class variable");
- $$ = 0;
- }
- ;
-
-f_norm_arg : f_bad_arg
- {
- $$ = 0;
- }
- | tIDENTIFIER
- {
- local_add_f(p, $1);
- $$ = $1;
- }
- ;
-
-f_arg_item : f_norm_arg
- {
- $$ = new_arg(p, $1);
- }
- | tLPAREN f_margs rparen
- {
- $$ = new_masgn(p, $2, 0);
- }
- ;
-
-f_arg : f_arg_item
- {
- $$ = list1($1);
- }
- | f_arg ',' f_arg_item
- {
- $$ = push($1, $3);
- }
- ;
-
-f_opt : tIDENTIFIER '=' arg_value
- {
- local_add_f(p, $1);
- $$ = cons(nsym($1), $3);
- }
- ;
-
-f_block_opt : tIDENTIFIER '=' primary_value
- {
- local_add_f(p, $1);
- $$ = cons(nsym($1), $3);
- }
- ;
-
-f_block_optarg : f_block_opt
- {
- $$ = list1($1);
- }
- | f_block_optarg ',' f_block_opt
- {
- $$ = push($1, $3);
- }
- ;
-
-f_optarg : f_opt
- {
- $$ = list1($1);
- }
- | f_optarg ',' f_opt
- {
- $$ = push($1, $3);
- }
- ;
-
-restarg_mark : '*'
- | tSTAR
- ;
-
-f_rest_arg : restarg_mark tIDENTIFIER
- {
- local_add_f(p, $2);
- $$ = $2;
- }
- | restarg_mark
- {
- local_add_f(p, 0);
- $$ = -1;
- }
- ;
-
-blkarg_mark : '&'
- | tAMPER
- ;
-
-f_block_arg : blkarg_mark tIDENTIFIER
- {
- local_add_f(p, $2);
- $$ = $2;
- }
- ;
-
-opt_f_block_arg : ',' f_block_arg
- {
- $$ = $2;
- }
- | none
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- ;
-
-singleton : var_ref
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- | '(' {p->lstate = EXPR_BEG;} expr rparen
- {
- if ($3 == 0) {
- yyerror(p, "can't define singleton method for ().");
- }
- else {
- switch ((enum node_type)(int)(intptr_t)$3->car) {
- case NODE_STR:
- case NODE_DSTR:
- case NODE_XSTR:
- case NODE_DXSTR:
- case NODE_DREGX:
- case NODE_MATCH:
- case NODE_FLOAT:
- case NODE_ARRAY:
- case NODE_HEREDOC:
- yyerror(p, "can't define singleton method for literals");
- default:
- break;
- }
- }
- $$ = $3;
- }
- ;
-
-assoc_list : none
- | assocs trailer
- {
- $$ = $1;
- }
- ;
-
-assocs : assoc
- {
- $$ = list1($1);
- }
- | assocs ',' assoc
- {
- $$ = push($1, $3);
- }
- ;
-
-assoc : arg_value tASSOC arg_value
- {
- $$ = cons($1, $3);
- }
- | tLABEL arg_value
- {
- $$ = cons(new_sym(p, $1), $2);
- }
- ;
-
-operation : tIDENTIFIER
- | tCONSTANT
- | tFID
- ;
-
-operation2 : tIDENTIFIER
- | tCONSTANT
- | tFID
- | op
- ;
-
-operation3 : tIDENTIFIER
- | tFID
- | op
- ;
-
-dot_or_colon : '.'
- | tCOLON2
- ;
-
-opt_terms : /* none */
- | terms
- ;
-
-opt_nl : /* none */
- | nl
- ;
-
-rparen : opt_nl ')'
- ;
-
-rbracket : opt_nl ']'
- ;
-
-trailer : /* none */
- | nl
- | ','
- ;
-
-term : ';' {yyerrok;}
- | nl
- ;
-
-nl : '\n'
- {
- p->lineno++;
- p->column = 0;
- }
- opt_heredoc_bodies
-
-terms : term
- | terms ';' {yyerrok;}
- ;
-
-none : /* none */
- {
- $$ = 0;
- }
- ;
+ | string_rep string_interp
+ {
+ $$ = append($1, $2);
+ }
+ ;
+
+string_interp : tSTRING_MID
+ {
+ $$ = list1($1);
+ }
+ | tSTRING_PART
+ {
+ $<nd>$ = p->lex_strterm;
+ p->lex_strterm = NULL;
+ }
+ compstmt
+ '}'
+ {
+ p->lex_strterm = $<nd>2;
+ $$ = list2($1, $3);
+ }
+ | tLITERAL_DELIM
+ {
+ $$ = list1(new_literal_delim(p));
+ }
+ | tHD_LITERAL_DELIM heredoc_bodies
+ {
+ $$ = list1(new_literal_delim(p));
+ }
+ ;
+
+xstring : tXSTRING_BEG tXSTRING
+ {
+ $$ = $2;
+ }
+ | tXSTRING_BEG string_rep tXSTRING
+ {
+ $$ = new_dxstr(p, push($2, $3));
+ }
+ ;
+
+regexp : tREGEXP_BEG tREGEXP
+ {
+ $$ = $2;
+ }
+ | tREGEXP_BEG string_rep tREGEXP
+ {
+ $$ = new_dregx(p, $2, $3);
+ }
+ ;
+
+heredoc : tHEREDOC_BEG
+ ;
+
+opt_heredoc_bodies : /* none */
+ | heredoc_bodies
+ ;
+
+heredoc_bodies : heredoc_body
+ | heredoc_bodies heredoc_body
+ ;
+
+heredoc_body : tHEREDOC_END
+ {
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ inf->doc = push(inf->doc, new_str(p, "", 0));
+ heredoc_end(p);
+ }
+ | heredoc_string_rep tHEREDOC_END
+ {
+ heredoc_end(p);
+ }
+ ;
+
+heredoc_string_rep : heredoc_string_interp
+ | heredoc_string_rep heredoc_string_interp
+ ;
+
+heredoc_string_interp : tHD_STRING_MID
+ {
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ inf->doc = push(inf->doc, $1);
+ heredoc_treat_nextline(p);
+ }
+ | tHD_STRING_PART
+ {
+ $<nd>$ = p->lex_strterm;
+ p->lex_strterm = NULL;
+ }
+ compstmt
+ '}'
+ {
+ parser_heredoc_info * inf = parsing_heredoc_inf(p);
+ p->lex_strterm = $<nd>2;
+ inf->doc = push(push(inf->doc, $1), $3);
+ }
+ ;
+
+words : tWORDS_BEG tSTRING
+ {
+ $$ = new_words(p, list1($2));
+ }
+ | tWORDS_BEG string_rep tSTRING
+ {
+ $$ = new_words(p, push($2, $3));
+ }
+ ;
+
+
+symbol : basic_symbol
+ {
+ $$ = new_sym(p, $1);
+ }
+ | tSYMBEG tSTRING_BEG string_interp tSTRING
+ {
+ p->lstate = EXPR_END;
+ $$ = new_dsym(p, push($3, $4));
+ }
+ ;
+
+basic_symbol : tSYMBEG sym
+ {
+ p->lstate = EXPR_END;
+ $$ = $2;
+ }
+ ;
+
+sym : fname
+ | tIVAR
+ | tGVAR
+ | tCVAR
+ | tSTRING
+ {
+ $$ = new_strsym(p, $1);
+ }
+ | tSTRING_BEG tSTRING
+ {
+ $$ = new_strsym(p, $2);
+ }
+ ;
+
+symbols : tSYMBOLS_BEG tSTRING
+ {
+ $$ = new_symbols(p, list1($2));
+ }
+ | tSYMBOLS_BEG string_rep tSTRING
+ {
+ $$ = new_symbols(p, push($2, $3));
+ }
+ ;
+
+numeric : tINTEGER
+ | tFLOAT
+ | tUMINUS_NUM tINTEGER %prec tLOWEST
+ {
+ $$ = negate_lit(p, $2);
+ }
+ | tUMINUS_NUM tFLOAT %prec tLOWEST
+ {
+ $$ = negate_lit(p, $2);
+ }
+ ;
+
+variable : tIDENTIFIER
+ {
+ $$ = new_lvar(p, $1);
+ }
+ | tIVAR
+ {
+ $$ = new_ivar(p, $1);
+ }
+ | tGVAR
+ {
+ $$ = new_gvar(p, $1);
+ }
+ | tCVAR
+ {
+ $$ = new_cvar(p, $1);
+ }
+ | tCONSTANT
+ {
+ $$ = new_const(p, $1);
+ }
+ ;
+
+var_lhs : variable
+ {
+ assignable(p, $1);
+ }
+ ;
+
+var_ref : variable
+ {
+ $$ = var_reference(p, $1);
+ }
+ | keyword_nil
+ {
+ $$ = new_nil(p);
+ }
+ | keyword_self
+ {
+ $$ = new_self(p);
+ }
+ | keyword_true
+ {
+ $$ = new_true(p);
+ }
+ | keyword_false
+ {
+ $$ = new_false(p);
+ }
+ | keyword__FILE__
+ {
+ if (!p->filename) {
+ p->filename = "(null)";
+ }
+ $$ = new_str(p, p->filename, strlen(p->filename));
+ }
+ | keyword__LINE__
+ {
+ char buf[16];
+
+ snprintf(buf, sizeof(buf), "%d", p->lineno);
+ $$ = new_int(p, buf, 10);
+ }
+ ;
+
+backref : tNTH_REF
+ | tBACK_REF
+ ;
+
+superclass : term
+ {
+ $$ = 0;
+ }
+ | '<'
+ {
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ }
+ expr_value term
+ {
+ $$ = $3;
+ }
+ | error term
+ {
+ yyerrok;
+ $$ = 0;
+ }
+ ;
+
+f_arglist : '(' f_args rparen
+ {
+ $$ = $2;
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ }
+ | f_args term
+ {
+ $$ = $1;
+ }
+ ;
+
+f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, $5, 0, $6);
+ }
+ | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8);
+ }
+ | f_arg ',' f_optarg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, 0, 0, $4);
+ }
+ | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, $3, 0, $5, $6);
+ }
+ | f_arg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, $3, 0, $4);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, $3, $5, $6);
+ }
+ | f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, $1, 0, 0, 0, $2);
+ }
+ | f_optarg ',' f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, $3, 0, $4);
+ }
+ | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, $3, $5, $6);
+ }
+ | f_optarg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, 0, 0, $2);
+ }
+ | f_optarg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, $1, 0, $3, $4);
+ }
+ | f_rest_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, 0, $1, 0, $2);
+ }
+ | f_rest_arg ',' f_arg opt_f_block_arg
+ {
+ $$ = new_args(p, 0, 0, $1, $3, $4);
+ }
+ | f_block_arg
+ {
+ $$ = new_args(p, 0, 0, 0, 0, $1);
+ }
+ | /* none */
+ {
+ local_add_f(p, 0);
+ $$ = new_args(p, 0, 0, 0, 0, 0);
+ }
+ ;
+
+f_bad_arg : tCONSTANT
+ {
+ yyerror(p, "formal argument cannot be a constant");
+ $$ = 0;
+ }
+ | tIVAR
+ {
+ yyerror(p, "formal argument cannot be an instance variable");
+ $$ = 0;
+ }
+ | tGVAR
+ {
+ yyerror(p, "formal argument cannot be a global variable");
+ $$ = 0;
+ }
+ | tCVAR
+ {
+ yyerror(p, "formal argument cannot be a class variable");
+ $$ = 0;
+ }
+ ;
+
+f_norm_arg : f_bad_arg
+ {
+ $$ = 0;
+ }
+ | tIDENTIFIER
+ {
+ local_add_f(p, $1);
+ $$ = $1;
+ }
+ ;
+
+f_arg_item : f_norm_arg
+ {
+ $$ = new_arg(p, $1);
+ }
+ | tLPAREN f_margs rparen
+ {
+ $$ = new_masgn(p, $2, 0);
+ }
+ ;
+
+f_arg : f_arg_item
+ {
+ $$ = list1($1);
+ }
+ | f_arg ',' f_arg_item
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+f_opt : tIDENTIFIER '=' arg_value
+ {
+ local_add_f(p, $1);
+ $$ = cons(nsym($1), $3);
+ }
+ ;
+
+f_block_opt : tIDENTIFIER '=' primary_value
+ {
+ local_add_f(p, $1);
+ $$ = cons(nsym($1), $3);
+ }
+ ;
+
+f_block_optarg : f_block_opt
+ {
+ $$ = list1($1);
+ }
+ | f_block_optarg ',' f_block_opt
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+f_optarg : f_opt
+ {
+ $$ = list1($1);
+ }
+ | f_optarg ',' f_opt
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+restarg_mark : '*'
+ | tSTAR
+ ;
+
+f_rest_arg : restarg_mark tIDENTIFIER
+ {
+ local_add_f(p, $2);
+ $$ = $2;
+ }
+ | restarg_mark
+ {
+ local_add_f(p, 0);
+ $$ = -1;
+ }
+ ;
+
+blkarg_mark : '&'
+ | tAMPER
+ ;
+
+f_block_arg : blkarg_mark tIDENTIFIER
+ {
+ local_add_f(p, $2);
+ $$ = $2;
+ }
+ ;
+
+opt_f_block_arg : ',' f_block_arg
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ local_add_f(p, 0);
+ $$ = 0;
+ }
+ ;
+
+singleton : var_ref
+ {
+ $$ = $1;
+ if (!$$) $$ = new_nil(p);
+ }
+ | '(' {p->lstate = EXPR_BEG;} expr rparen
+ {
+ if ($3 == 0) {
+ yyerror(p, "can't define singleton method for ().");
+ }
+ else {
+ switch ((enum node_type)(int)(intptr_t)$3->car) {
+ case NODE_STR:
+ case NODE_DSTR:
+ case NODE_XSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_MATCH:
+ case NODE_FLOAT:
+ case NODE_ARRAY:
+ case NODE_HEREDOC:
+ yyerror(p, "can't define singleton method for literals");
+ default:
+ break;
+ }
+ }
+ $$ = $3;
+ }
+ ;
+
+assoc_list : none
+ | assocs trailer
+ {
+ $$ = $1;
+ }
+ ;
+
+assocs : assoc
+ {
+ $$ = list1($1);
+ }
+ | assocs ',' assoc
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+assoc : arg_value tASSOC arg_value
+ {
+ $$ = cons($1, $3);
+ }
+ | tLABEL arg_value
+ {
+ $$ = cons(new_sym(p, $1), $2);
+ }
+ ;
+
+operation : tIDENTIFIER
+ | tCONSTANT
+ | tFID
+ ;
+
+operation2 : tIDENTIFIER
+ | tCONSTANT
+ | tFID
+ | op
+ ;
+
+operation3 : tIDENTIFIER
+ | tFID
+ | op
+ ;
+
+dot_or_colon : '.'
+ | tCOLON2
+ ;
+
+opt_terms : /* none */
+ | terms
+ ;
+
+opt_nl : /* none */
+ | nl
+ ;
+
+rparen : opt_nl ')'
+ ;
+
+rbracket : opt_nl ']'
+ ;
+
+trailer : /* none */
+ | nl
+ | ','
+ ;
+
+term : ';' {yyerrok;}
+ | nl
+ ;
+
+nl : '\n'
+ {
+ p->lineno++;
+ p->column = 0;
+ }
+ opt_heredoc_bodies
+
+terms : term
+ | terms ';' {yyerrok;}
+ ;
+
+none : /* none */
+ {
+ $$ = 0;
+ }
+ ;
%%
#define yylval (*((YYSTYPE*)(p->ylval)))
@@ -3206,15 +3318,18 @@ backref_error(parser_state *p, node *n)
if (c == NODE_NTH_REF) {
yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr);
- } else if (c == NODE_BACK_REF) {
+ }
+ else if (c == NODE_BACK_REF) {
yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
- } else {
- mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %d", c);
+ }
+ else {
+ mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
}
}
-static int peeks(parser_state *p, const char *s);
-static int skips(parser_state *p, const char *s);
+static void pushback(parser_state *p, int c);
+static mrb_bool peeks(parser_state *p, const char *s);
+static mrb_bool skips(parser_state *p, const char *s);
static inline int
nextc(parser_state *p)
@@ -3232,32 +3347,36 @@ nextc(parser_state *p)
else {
#ifdef ENABLE_STDIO
if (p->f) {
- if (feof(p->f)) goto end_retry;
+ if (feof(p->f)) goto eof;
c = fgetc(p->f);
- if (c == EOF) goto end_retry;
+ if (c == EOF) goto eof;
}
else
#endif
- if (!p->s || p->s >= p->send) {
- goto end_retry;
- }
- else {
- c = (unsigned char)*p->s++;
- }
+ if (!p->s || p->s >= p->send) {
+ goto eof;
+ }
+ else {
+ c = (unsigned char)*p->s++;
+ }
}
p->column++;
+ if (c == '\r') {
+ c = nextc(p);
+ if (c != '\n') {
+ pushback(p, c);
+ return '\r';
+ }
+ return c;
+ }
return c;
- end_retry:
+ eof:
if (!p->cxt) return -1;
else {
- mrbc_context *cxt = p->cxt;
-
- if (cxt->partial_hook(p) < 0) return -1;
- p->cxt = NULL;
- c = nextc(p);
- p->cxt = cxt;
- return c;
+ if (p->cxt->partial_hook(p) < 0)
+ return -1;
+ return -2;
}
}
@@ -3281,7 +3400,7 @@ skip(parser_state *p, char term)
}
}
-static int
+static mrb_bool
peek_n(parser_state *p, int c, int n)
{
node *list = 0;
@@ -3303,7 +3422,7 @@ peek_n(parser_state *p, int c, int n)
}
#define peek(p,c) peek_n((p), (c), 0)
-static int
+static mrb_bool
peeks(parser_state *p, const char *s)
{
int len = strlen(s);
@@ -3318,19 +3437,19 @@ peeks(parser_state *p, const char *s)
}
else
#endif
- if (p->s && p->s + len >= p->send) {
- if (memcmp(p->s, s, len) == 0) return TRUE;
- }
+ if (p->s && p->s + len >= p->send) {
+ if (memcmp(p->s, s, len) == 0) return TRUE;
+ }
return FALSE;
}
-static int
+static mrb_bool
skips(parser_state *p, const char *s)
{
int c;
for (;;) {
- // skip until first char
+ /* skip until first char */
for (;;) {
c = nextc(p);
if (c < 0) return c;
@@ -3341,11 +3460,11 @@ skips(parser_state *p, const char *s)
int len = strlen(s);
while (len--) {
- nextc(p);
+ nextc(p);
}
return TRUE;
}
- else{
+ else{
s--;
}
}
@@ -3361,10 +3480,48 @@ newtok(parser_state *p)
}
static void
-tokadd(parser_state *p, int c)
+tokadd(parser_state *p, int32_t c)
{
- if (p->bidx < MRB_PARSER_BUF_SIZE) {
- p->buf[p->bidx++] = c;
+ char utf8[4];
+ unsigned len;
+
+ /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */
+ if (c >= 0) {
+ /* Single byte from source or non-Unicode escape */
+ utf8[0] = (char)c;
+ len = 1;
+ }
+ else {
+ /* Unicode character */
+ c = -c;
+ if (c < 0x80) {
+ utf8[0] = (char)c;
+ len = 1;
+ }
+ else if (c < 0x800) {
+ utf8[0] = (char)(0xC0 | (c >> 6));
+ utf8[1] = (char)(0x80 | (c & 0x3F));
+ len = 2;
+ }
+ else if (c < 0x10000) {
+ utf8[0] = (char)(0xE0 | (c >> 12) );
+ utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F));
+ utf8[2] = (char)(0x80 | ( c & 0x3F));
+ len = 3;
+ }
+ else {
+ utf8[0] = (char)(0xF0 | (c >> 18) );
+ utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F));
+ utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F));
+ utf8[3] = (char)(0x80 | ( c & 0x3F));
+ len = 4;
+ }
+ }
+ if (p->bidx+len <= MRB_PARSER_BUF_SIZE) {
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ p->buf[p->bidx++] = utf8[i];
+ }
}
}
@@ -3418,15 +3575,15 @@ scan_oct(const int *start, int len, int *retlen)
return retval;
}
-static int
+static int32_t
scan_hex(const int *start, int len, int *retlen)
{
static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
- register const int *s = start;
- register int retval = 0;
+ const int *s = start;
+ int32_t retval = 0;
char *tmp;
- /* mrb_assert(len <= 2) */
+ /* mrb_assert(len <= 8) */
while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) {
retval <<= 4;
retval |= (tmp - hexdigit) & 15;
@@ -3437,80 +3594,131 @@ scan_hex(const int *start, int len, int *retlen)
return retval;
}
-static int
+/* Return negative to indicate Unicode code point */
+static int32_t
read_escape(parser_state *p)
{
- int c;
+ int32_t c;
switch (c = nextc(p)) {
- case '\\': /* Backslash */
+ case '\\':/* Backslash */
return c;
- case 'n': /* newline */
+ case 'n':/* newline */
return '\n';
- case 't': /* horizontal tab */
+ case 't':/* horizontal tab */
return '\t';
- case 'r': /* carriage-return */
+ case 'r':/* carriage-return */
return '\r';
- case 'f': /* form-feed */
+ case 'f':/* form-feed */
return '\f';
- case 'v': /* vertical tab */
+ case 'v':/* vertical tab */
return '\13';
- case 'a': /* alarm(bell) */
+ case 'a':/* alarm(bell) */
return '\007';
- case 'e': /* escape */
+ case 'e':/* escape */
return 033;
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- {
- int buf[3];
- int i;
+ {
+ int buf[3];
+ int i;
- buf[0] = c;
- for (i=1; i<3; i++) {
+ buf[0] = c;
+ for (i=1; i<3; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (buf[i] < '0' || '7' < buf[i]) {
+ pushback(p, buf[i]);
+ break;
+ }
+ }
+ c = scan_oct(buf, i, &i);
+ }
+ return c;
+
+ case 'x': /* hex constant */
+ {
+ int buf[2];
+ int i;
+
+ for (i=0; i<2; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (!ISXDIGIT(buf[i])) {
+ pushback(p, buf[i]);
+ break;
+ }
+ }
+ c = scan_hex(buf, i, &i);
+ if (i == 0) {
+ yyerror(p, "Invalid escape character syntax");
+ return 0;
+ }
+ }
+ return c;
+
+ case 'u': /* Unicode */
+ {
+ int buf[9];
+ int i;
+
+ /* Look for opening brace */
+ i = 0;
+ buf[0] = nextc(p);
+ if (buf[0] < 0) goto eof;
+ if (buf[0] == '{') {
+ /* \u{xxxxxxxx} form */
+ for (i=0; i<9; i++) {
buf[i] = nextc(p);
- if (buf[i] == -1) goto eof;
- if (buf[i] < '0' || '7' < buf[i]) {
- pushback(p, buf[i]);
+ if (buf[i] < 0) goto eof;
+ if (buf[i] == '}') {
break;
}
+ else if (!ISXDIGIT(buf[i])) {
+ yyerror(p, "Invalid escape character syntax");
+ pushback(p, buf[i]);
+ return 0;
+ }
}
- c = scan_oct(buf, i, &i);
}
- return c;
-
- case 'x': /* hex constant */
- {
- int buf[2];
- int i;
-
- for (i=0; i<2; i++) {
- buf[i] = nextc(p);
- if (buf[i] == -1) goto eof;
- if (!ISXDIGIT(buf[i])) {
- pushback(p, buf[i]);
- break;
- }
- }
- c = scan_hex(buf, i, &i);
- if (i == 0) {
- yyerror(p, "Invalid escape character syntax");
- return 0;
+ else if (ISXDIGIT(buf[0])) {
+ /* \uxxxx form */
+ for (i=1; i<4; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (!ISXDIGIT(buf[i])) {
+ pushback(p, buf[i]);
+ break;
+ }
}
}
- return c;
+ else {
+ pushback(p, buf[0]);
+ }
+ c = scan_hex(buf, i, &i);
+ if (i == 0) {
+ yyerror(p, "Invalid escape character syntax");
+ return 0;
+ }
+ if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
+ yyerror(p, "Invalid Unicode code point");
+ return 0;
+ }
+ }
+ return -c;
- case 'b': /* backspace */
+ case 'b':/* backspace */
return '\010';
- case 's': /* space */
+ case 's':/* space */
return ' ';
case 'M':
@@ -3522,7 +3730,7 @@ read_escape(parser_state *p)
if ((c = nextc(p)) == '\\') {
return read_escape(p) | 0x80;
}
- else if (c == -1) goto eof;
+ else if (c < 0) goto eof;
else {
return ((c & 0xff) | 0x80);
}
@@ -3539,11 +3747,12 @@ read_escape(parser_state *p)
}
else if (c == '?')
return 0177;
- else if (c == -1) goto eof;
+ else if (c < 0) goto eof;
return c & 0x9f;
- eof:
+ eof:
case -1:
+ case -2:
yyerror(p, "Invalid escape character syntax");
return '\0';
@@ -3552,7 +3761,6 @@ read_escape(parser_state *p)
}
}
-
static int
parse_string(parser_state *p)
{
@@ -3565,7 +3773,7 @@ parse_string(parser_state *p)
newtok(p);
while ((c = nextc(p)) != end || nest_level != 0) {
- if (hinf && (c == '\n' || c == -1)) {
+ if (hinf && (c == '\n' || c < 0)) {
int line_head;
tokadd(p, '\n');
tokfix(p);
@@ -3574,29 +3782,29 @@ parse_string(parser_state *p)
line_head = hinf->line_head;
hinf->line_head = TRUE;
if (line_head) {
- /* check whether end of heredoc */
- const char *s = tok(p);
- int len = toklen(p);
- if (hinf->allow_indent) {
- while (ISSPACE(*s) && len > 0) {
- ++s;
- --len;
- }
- }
- if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
- return tHEREDOC_END;
- }
+ /* check whether end of heredoc */
+ const char *s = tok(p);
+ int len = toklen(p);
+ if (hinf->allow_indent) {
+ while (ISSPACE(*s) && len > 0) {
+ ++s;
+ --len;
+ }
+ }
+ if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
+ return tHEREDOC_END;
+ }
}
- if (c == -1) {
- char buf[256];
- snprintf(buf, sizeof(buf), "can't find string \"%s\" anywhere before EOF", hinf->term);
- yyerror(p, buf);
- return 0;
+ if (c < 0) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
+ yyerror(p, buf);
+ return 0;
}
yylval.nd = new_str(p, tok(p), toklen(p));
- return tSTRING_MID;
+ return tHD_STRING_MID;
}
- if (c == -1) {
+ if (c < 0) {
yyerror(p, "unterminated string meets end of file");
return 0;
}
@@ -3611,56 +3819,53 @@ parse_string(parser_state *p)
else if (c == '\\') {
c = nextc(p);
if (type & STR_FUNC_EXPAND) {
- if (c == end || c == beg) {
- tokadd(p, c);
- }
- else if ((c == '\n') && (type & STR_FUNC_ARRAY)) {
- p->lineno++;
- p->column = 0;
- tokadd(p, '\n');
- }
- else {
- if (type & STR_FUNC_REGEXP) {
- tokadd(p, '\\');
- if (c != -1)
- tokadd(p, c);
- } else {
- pushback(p, c);
- tokadd(p, read_escape(p));
- }
- if (hinf)
- hinf->line_head = FALSE;
- }
- } else {
- if (c != beg && c != end) {
- switch (c) {
- case '\n':
- p->lineno++;
- p->column = 0;
- break;
-
- case '\\':
- break;
-
- default:
- if (! ISSPACE(c))
- tokadd(p, '\\');
- }
- }
- tokadd(p, c);
+ if (c == end || c == beg) {
+ tokadd(p, c);
+ }
+ else if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ if (type & STR_FUNC_ARRAY) {
+ tokadd(p, '\n');
+ }
+ }
+ else if (type & STR_FUNC_REGEXP) {
+ tokadd(p, '\\');
+ tokadd(p, c);
+ }
+ else {
+ pushback(p, c);
+ tokadd(p, read_escape(p));
+ if (hinf)
+ hinf->line_head = FALSE;
+ }
+ }
+ else {
+ if (c != beg && c != end) {
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ }
+ if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) {
+ tokadd(p, '\\');
+ }
+ }
+ tokadd(p, c);
}
continue;
}
else if ((c == '#') && (type & STR_FUNC_EXPAND)) {
c = nextc(p);
if (c == '{') {
- tokfix(p);
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- yylval.nd = new_str(p, tok(p), toklen(p));
- if (hinf)
- hinf->line_head = FALSE;
- return tSTRING_PART;
+ tokfix(p);
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ yylval.nd = new_str(p, tok(p), toklen(p));
+ if (hinf) {
+ hinf->line_head = FALSE;
+ return tHD_STRING_PART;
+ }
+ return tSTRING_PART;
}
tokadd(p, '#');
pushback(p, c);
@@ -3668,24 +3873,27 @@ parse_string(parser_state *p)
}
if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) {
if (toklen(p) == 0) {
- do {
- if (c == '\n') {
- p->lineno++;
- p->column = 0;
- }
- } while (ISSPACE(c = nextc(p)));
- pushback(p, c);
- return tLITERAL_DELIM;
- } else {
- pushback(p, c);
- tokfix(p);
- yylval.nd = new_str(p, tok(p), toklen(p));
- return tSTRING_MID;
+ do {
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ heredoc_treat_nextline(p);
+ if (p->parsing_heredoc != NULL) {
+ return tHD_LITERAL_DELIM;
+ }
+ }
+ } while (ISSPACE(c = nextc(p)));
+ pushback(p, c);
+ return tLITERAL_DELIM;
+ }
+ else {
+ pushback(p, c);
+ tokfix(p);
+ yylval.nd = new_str(p, tok(p), toklen(p));
+ return tSTRING_MID;
}
}
-
tokadd(p, c);
-
}
tokfix(p);
@@ -3701,10 +3909,12 @@ parse_string(parser_state *p)
int f = 0;
int c;
char *s = strndup(tok(p), toklen(p));
- char flag[4] = { '\0' };
+ char flags[3];
+ char *flag = flags;
+ char *dup;
newtok(p);
- while (c = nextc(p), ISALPHA(c)) {
+ while (c = nextc(p), c >= 0 && ISALPHA(c)) {
switch (c) {
case 'i': f |= 1; break;
case 'x': f |= 2; break;
@@ -3717,13 +3927,19 @@ parse_string(parser_state *p)
char msg[128];
tokfix(p);
snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
- toklen(p) > 1 ? "s" : "", tok(p));
+ toklen(p) > 1 ? "s" : "", tok(p));
yyerror(p, msg);
}
- if (f & 1) strcat(flag, "i");
- if (f & 2) strcat(flag, "x");
- if (f & 4) strcat(flag, "m");
- yylval.nd = new_regx(p, s, strdup(flag));
+ if (f != 0) {
+ if (f & 1) *flag++ = 'i';
+ if (f & 2) *flag++ = 'x';
+ if (f & 4) *flag++ = 'm';
+ dup = strndup(flags, (size_t)(flag - flags));
+ }
+ else {
+ dup = NULL;
+ }
+ yylval.nd = new_regx(p, s, dup);
return tREGEXP;
}
@@ -3738,8 +3954,8 @@ heredoc_identifier(parser_state *p)
{
int c;
int type = str_heredoc;
- int indent = FALSE;
- int quote = FALSE;
+ mrb_bool indent = FALSE;
+ mrb_bool quote = FALSE;
node *newnode;
parser_heredoc_info *info;
@@ -3757,18 +3973,22 @@ heredoc_identifier(parser_state *p)
if (c == '\'')
quote = TRUE;
newtok(p);
- while ((c = nextc(p)) != -1 && c != term) {
+ while ((c = nextc(p)) >= 0 && c != term) {
if (c == '\n') {
- c = -1;
- break;
+ c = -1;
+ break;
}
tokadd(p, c);
}
- if (c == -1) {
+ if (c < 0) {
yyerror(p, "unterminated here document identifier");
return 0;
}
- } else {
+ }
+ else {
+ if (c < 0) {
+ return 0; /* missing here document identifier */
+ }
if (! identchar(c)) {
pushback(p, c);
if (indent) pushback(p, '-');
@@ -3777,7 +3997,7 @@ heredoc_identifier(parser_state *p)
newtok(p);
do {
tokadd(p, c);
- } while ((c = nextc(p)) != -1 && identchar(c));
+ } while ((c = nextc(p)) >= 0 && identchar(c));
pushback(p, c);
}
tokfix(p);
@@ -3791,14 +4011,7 @@ heredoc_identifier(parser_state *p)
info->allow_indent = indent;
info->line_head = TRUE;
info->doc = NULL;
- p->heredocs = push(p->heredocs, newnode);
- if (p->parsing_heredoc == NULL) {
- node *n = p->heredocs;
- while (n->cdr)
- n = n->cdr;
- p->parsing_heredoc = n;
- }
- p->heredoc_starts_nextline = TRUE;
+ p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
p->lstate = EXPR_END;
yylval.nd = newnode;
@@ -3817,7 +4030,7 @@ arg_ambiguous(parser_state *p)
static int
parser_yylex(parser_state *p)
{
- register int c;
+ int32_t c;
int space_seen = 0;
int cmd_state;
enum mrb_lex_state_enum last_state;
@@ -3825,21 +4038,24 @@ parser_yylex(parser_state *p)
if (p->lex_strterm) {
if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
- if ((p->parsing_heredoc != NULL) && (! p->heredoc_starts_nextline))
- return parse_string(p);
+ if (p->parsing_heredoc != NULL)
+ return parse_string(p);
}
else
return parse_string(p);
}
cmd_state = p->cmd_start;
p->cmd_start = FALSE;
- retry:
+ retry:
last_state = p->lstate;
switch (c = nextc(p)) {
case '\0': /* NUL */
case '\004': /* ^D */
case '\032': /* ^Z */
+ return 0;
case -1: /* end of script. */
+ if (p->heredocs_from_nextline)
+ goto maybe_heredoc;
return 0;
/* white spaces */
@@ -3850,80 +4066,86 @@ parser_yylex(parser_state *p)
case '#': /* it's a comment */
skip(p, '\n');
- /* fall through */
+ /* fall through */
+ case -2: /* end of partial script. */
case '\n':
- p->heredoc_starts_nextline = FALSE;
+ maybe_heredoc:
+ heredoc_treat_nextline(p);
+ switch (p->lstate) {
+ case EXPR_BEG:
+ case EXPR_FNAME:
+ case EXPR_DOT:
+ case EXPR_CLASS:
+ case EXPR_VALUE:
+ p->lineno++;
+ p->column = 0;
if (p->parsing_heredoc != NULL) {
- p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0);
- goto normal_newline;
+ return parse_string(p);
}
- switch (p->lstate) {
- case EXPR_BEG:
- case EXPR_FNAME:
- case EXPR_DOT:
- case EXPR_CLASS:
- case EXPR_VALUE:
- p->lineno++;
- p->column = 0;
- goto retry;
- default:
+ goto retry;
+ default:
+ break;
+ }
+ if (p->parsing_heredoc != NULL) {
+ return '\n';
+ }
+ while ((c = nextc(p))) {
+ switch (c) {
+ case ' ': case '\t': case '\f': case '\r':
+ case '\13': /* '\v' */
+ space_seen = 1;
break;
- }
- while ((c = nextc(p))) {
- switch (c) {
- case ' ': case '\t': case '\f': case '\r':
- case '\13': /* '\v' */
- space_seen = 1;
- break;
- case '.':
- if ((c = nextc(p)) != '.') {
- pushback(p, c);
- pushback(p, '.');
- goto retry;
- }
- case -1: /* EOF */
- goto normal_newline;
- default:
- pushback(p, c);
- goto normal_newline;
+ case '.':
+ if ((c = nextc(p)) != '.') {
+ pushback(p, c);
+ pushback(p, '.');
+ goto retry;
}
+ case -1: /* EOF */
+ case -2: /* end of partial script */
+ goto normal_newline;
+ default:
+ pushback(p, c);
+ goto normal_newline;
}
+ }
normal_newline:
- p->cmd_start = TRUE;
- p->lstate = EXPR_BEG;
- return '\n';
+ p->cmd_start = TRUE;
+ p->lstate = EXPR_BEG;
+ return '\n';
case '*':
if ((c = nextc(p)) == '*') {
if ((c = nextc(p)) == '=') {
- yylval.id = intern2("**",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern("**",2);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
c = tPOW;
}
else {
if (c == '=') {
- yylval.id = intern_c('*');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern_c('*');
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
if (IS_SPCARG(c)) {
- yywarning(p, "`*' interpreted as argument prefix");
- c = tSTAR;
+ yywarning(p, "`*' interpreted as argument prefix");
+ c = tSTAR;
}
else if (IS_BEG()) {
- c = tSTAR;
+ c = tSTAR;
}
else {
- c = '*';
+ c = '*';
}
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
return c;
@@ -3933,7 +4155,7 @@ parser_yylex(parser_state *p)
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
if (c == '@') {
- return '!';
+ return '!';
}
}
else {
@@ -3951,18 +4173,19 @@ parser_yylex(parser_state *p)
case '=':
if (p->column == 1) {
if (peeks(p, "begin\n")) {
- skips(p, "\n=end\n");
- goto retry;
+ skips(p, "\n=end\n");
+ goto retry;
}
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
if ((c = nextc(p)) == '=') {
if ((c = nextc(p)) == '=') {
- return tEQQ;
+ return tEQQ;
}
pushback(p, c);
return tEQ;
@@ -3980,34 +4203,35 @@ parser_yylex(parser_state *p)
last_state = p->lstate;
c = nextc(p);
if (c == '<' &&
- p->lstate != EXPR_DOT &&
- p->lstate != EXPR_CLASS &&
- !IS_END() &&
- (!IS_ARG() || space_seen)) {
+ p->lstate != EXPR_DOT &&
+ p->lstate != EXPR_CLASS &&
+ !IS_END() &&
+ (!IS_ARG() || space_seen)) {
int token = heredoc_identifier(p);
if (token)
- return token;
+ return token;
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
if (p->lstate == EXPR_CLASS) {
- p->cmd_start = TRUE;
+ p->cmd_start = TRUE;
}
}
if (c == '=') {
if ((c = nextc(p)) == '>') {
- return tCMP;
+ return tCMP;
}
pushback(p, c);
return tLEQ;
}
if (c == '<') {
if ((c = nextc(p)) == '=') {
- yylval.id = intern2("<<",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern("<<",2);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
return tLSHFT;
@@ -4018,7 +4242,8 @@ parser_yylex(parser_state *p)
case '>':
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
if ((c = nextc(p)) == '=') {
@@ -4026,9 +4251,9 @@ parser_yylex(parser_state *p)
}
if (c == '>') {
if ((c = nextc(p)) == '=') {
- yylval.id = intern2(">>",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern(">>",2);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
return tRSHFT;
@@ -4065,68 +4290,59 @@ parser_yylex(parser_state *p)
return '?';
}
c = nextc(p);
- if (c == -1) {
+ if (c < 0) {
yyerror(p, "incomplete character syntax");
return 0;
}
if (isspace(c)) {
if (!IS_ARG()) {
- int c2;
- switch (c) {
- case ' ':
- c2 = 's';
- break;
- case '\n':
- c2 = 'n';
- break;
- case '\t':
- c2 = 't';
- break;
- case '\v':
- c2 = 'v';
- break;
- case '\r':
- c2 = 'r';
- break;
- case '\f':
- c2 = 'f';
- break;
- default:
- c2 = 0;
- break;
- }
- if (c2) {
- char buf[256];
- snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
- yyerror(p, buf);
- }
+ int c2;
+ switch (c) {
+ case ' ':
+ c2 = 's';
+ break;
+ case '\n':
+ c2 = 'n';
+ break;
+ case '\t':
+ c2 = 't';
+ break;
+ case '\v':
+ c2 = 'v';
+ break;
+ case '\r':
+ c2 = 'r';
+ break;
+ case '\f':
+ c2 = 'f';
+ break;
+ default:
+ c2 = 0;
+ break;
+ }
+ if (c2) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+ yyerror(p, buf);
+ }
}
- ternary:
+ ternary:
pushback(p, c);
p->lstate = EXPR_VALUE;
return '?';
}
token_column = newtok(p);
- // need support UTF-8 if configured
+ /* need support UTF-8 if configured */
if ((isalnum(c) || c == '_')) {
int c2 = nextc(p);
pushback(p, c2);
if ((isalnum(c2) || c2 == '_')) {
- goto ternary;
+ goto ternary;
}
}
if (c == '\\') {
- c = nextc(p);
- if (c == 'u') {
-#if 0
- tokadd_utf8(p);
-#endif
- }
- else {
- pushback(p, c);
- c = read_escape(p);
- tokadd(p, c);
- }
+ c = read_escape(p);
+ tokadd(p, c);
}
else {
tokadd(p, c);
@@ -4140,9 +4356,9 @@ parser_yylex(parser_state *p)
if ((c = nextc(p)) == '&') {
p->lstate = EXPR_BEG;
if ((c = nextc(p)) == '=') {
- yylval.id = intern2("&&",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern("&&",2);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
return tANDOP;
@@ -4165,7 +4381,8 @@ parser_yylex(parser_state *p)
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
return c;
@@ -4174,9 +4391,9 @@ parser_yylex(parser_state *p)
if ((c = nextc(p)) == '|') {
p->lstate = EXPR_BEG;
if ((c = nextc(p)) == '=') {
- yylval.id = intern2("||",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
+ yylval.id = intern("||",2);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
}
pushback(p, c);
return tOROP;
@@ -4200,7 +4417,7 @@ parser_yylex(parser_state *p)
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
if (c == '@') {
- return tUPLUS;
+ return tUPLUS;
}
pushback(p, c);
return '+';
@@ -4213,9 +4430,9 @@ parser_yylex(parser_state *p)
if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
p->lstate = EXPR_BEG;
pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- c = '+';
- goto start_num;
+ if (c >= 0 && ISDIGIT(c)) {
+ c = '+';
+ goto start_num;
}
return tUPLUS;
}
@@ -4228,7 +4445,7 @@ parser_yylex(parser_state *p)
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
if (c == '@') {
- return tUMINUS;
+ return tUMINUS;
}
pushback(p, c);
return '-';
@@ -4245,8 +4462,8 @@ parser_yylex(parser_state *p)
if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
p->lstate = EXPR_BEG;
pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- return tUMINUS_NUM;
+ if (c >= 0 && ISDIGIT(c)) {
+ return tUMINUS_NUM;
}
return tUMINUS;
}
@@ -4258,244 +4475,244 @@ parser_yylex(parser_state *p)
p->lstate = EXPR_BEG;
if ((c = nextc(p)) == '.') {
if ((c = nextc(p)) == '.') {
- return tDOT3;
+ return tDOT3;
}
pushback(p, c);
return tDOT2;
}
pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
+ if (c >= 0 && ISDIGIT(c)) {
yyerror(p, "no .<digit> floating literal anymore; put 0 before dot");
}
p->lstate = EXPR_DOT;
return '.';
- start_num:
+ start_num:
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- {
- int is_float, seen_point, seen_e, nondigit;
+ {
+ int is_float, seen_point, seen_e, nondigit;
- is_float = seen_point = seen_e = nondigit = 0;
- p->lstate = EXPR_END;
- token_column = newtok(p);
- if (c == '-' || c == '+') {
- tokadd(p, c);
- c = nextc(p);
- }
- if (c == '0') {
+ is_float = seen_point = seen_e = nondigit = 0;
+ p->lstate = EXPR_END;
+ token_column = newtok(p);
+ if (c == '-' || c == '+') {
+ tokadd(p, c);
+ c = nextc(p);
+ }
+ if (c == '0') {
#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0)
- int start = toklen(p);
- c = nextc(p);
- if (c == 'x' || c == 'X') {
- /* hexadecimal */
- c = nextc(p);
- if (c != -1 && ISXDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISXDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, tolower(c));
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 16);
- return tINTEGER;
- }
- if (c == 'b' || c == 'B') {
- /* binary */
- c = nextc(p);
- if (c == '0' || c == '1') {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c != '0' && c != '1') break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 2);
- return tINTEGER;
- }
- if (c == 'd' || c == 'D') {
- /* decimal */
- c = nextc(p);
- if (c != -1 && ISDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 10);
- return tINTEGER;
- }
- if (c == '_') {
- /* 0_0 */
- goto octal_number;
- }
- if (c == 'o' || c == 'O') {
- /* prefixed octal */
- c = nextc(p);
- if (c == -1 || c == '_' || !ISDIGIT(c)) {
- no_digits();
- }
- }
- if (c >= '0' && c <= '7') {
- /* octal */
- octal_number:
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c < '0' || c > '9') break;
- if (c > '7') goto invalid_octal;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
-
- if (toklen(p) > start) {
- pushback(p, c);
- tokfix(p);
- if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 8);
- return tINTEGER;
- }
- if (nondigit) {
- pushback(p, c);
- goto trailing_uc;
- }
- }
- if (c > '7' && c <= '9') {
- invalid_octal:
- yyerror(p, "Invalid octal digit");
- }
- else if (c == '.' || c == 'e' || c == 'E') {
- tokadd(p, '0');
- }
- else {
- pushback(p, c);
- yylval.nd = new_int(p, "0", 10);
- return tINTEGER;
- }
+ int start = toklen(p);
+ c = nextc(p);
+ if (c == 'x' || c == 'X') {
+ /* hexadecimal */
+ c = nextc(p);
+ if (c >= 0 && ISXDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISXDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, tolower(c));
+ } while ((c = nextc(p)) >= 0);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ no_digits();
+ }
+ else if (nondigit) goto trailing_uc;
+ yylval.nd = new_int(p, tok(p), 16);
+ return tINTEGER;
+ }
+ if (c == 'b' || c == 'B') {
+ /* binary */
+ c = nextc(p);
+ if (c == '0' || c == '1') {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c != '0' && c != '1') break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) >= 0);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ no_digits();
+ }
+ else if (nondigit) goto trailing_uc;
+ yylval.nd = new_int(p, tok(p), 2);
+ return tINTEGER;
+ }
+ if (c == 'd' || c == 'D') {
+ /* decimal */
+ c = nextc(p);
+ if (c >= 0 && ISDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) >= 0);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ no_digits();
+ }
+ else if (nondigit) goto trailing_uc;
+ yylval.nd = new_int(p, tok(p), 10);
+ return tINTEGER;
+ }
+ if (c == '_') {
+ /* 0_0 */
+ goto octal_number;
+ }
+ if (c == 'o' || c == 'O') {
+ /* prefixed octal */
+ c = nextc(p);
+ if (c < 0 || c == '_' || !ISDIGIT(c)) {
+ no_digits();
+ }
+ }
+ if (c >= '0' && c <= '7') {
+ /* octal */
+ octal_number:
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c < '0' || c > '9') break;
+ if (c > '7') goto invalid_octal;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) >= 0);
+
+ if (toklen(p) > start) {
+ pushback(p, c);
+ tokfix(p);
+ if (nondigit) goto trailing_uc;
+ yylval.nd = new_int(p, tok(p), 8);
+ return tINTEGER;
+ }
+ if (nondigit) {
+ pushback(p, c);
+ goto trailing_uc;
+ }
+ }
+ if (c > '7' && c <= '9') {
+ invalid_octal:
+ yyerror(p, "Invalid octal digit");
+ }
+ else if (c == '.' || c == 'e' || c == 'E') {
+ tokadd(p, '0');
}
+ else {
+ pushback(p, c);
+ yylval.nd = new_int(p, "0", 10);
+ return tINTEGER;
+ }
+ }
- for (;;) {
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- nondigit = 0;
- tokadd(p, c);
- break;
-
- case '.':
- if (nondigit) goto trailing_uc;
- if (seen_point || seen_e) {
- goto decode_num;
- }
- else {
- int c0 = nextc(p);
- if (c0 == -1 || !ISDIGIT(c0)) {
- pushback(p, c0);
- goto decode_num;
- }
- c = c0;
- }
- tokadd(p, '.');
- tokadd(p, c);
- is_float++;
- seen_point++;
- nondigit = 0;
- break;
-
- case 'e':
- case 'E':
- if (nondigit) {
- pushback(p, c);
- c = nondigit;
- goto decode_num;
- }
- if (seen_e) {
- goto decode_num;
- }
- tokadd(p, c);
- seen_e++;
- is_float++;
- nondigit = c;
- c = nextc(p);
- if (c != '-' && c != '+') continue;
- tokadd(p, c);
- nondigit = c;
- break;
-
- case '_': /* `_' in number just ignored */
- if (nondigit) goto decode_num;
- nondigit = c;
- break;
-
- default:
- goto decode_num;
- }
- c = nextc(p);
+ for (;;) {
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ nondigit = 0;
+ tokadd(p, c);
+ break;
+
+ case '.':
+ if (nondigit) goto trailing_uc;
+ if (seen_point || seen_e) {
+ goto decode_num;
+ }
+ else {
+ int c0 = nextc(p);
+ if (c0 < 0 || !ISDIGIT(c0)) {
+ pushback(p, c0);
+ goto decode_num;
+ }
+ c = c0;
+ }
+ tokadd(p, '.');
+ tokadd(p, c);
+ is_float++;
+ seen_point++;
+ nondigit = 0;
+ break;
+
+ case 'e':
+ case 'E':
+ if (nondigit) {
+ pushback(p, c);
+ c = nondigit;
+ goto decode_num;
+ }
+ if (seen_e) {
+ goto decode_num;
+ }
+ tokadd(p, c);
+ seen_e++;
+ is_float++;
+ nondigit = c;
+ c = nextc(p);
+ if (c != '-' && c != '+') continue;
+ tokadd(p, c);
+ nondigit = c;
+ break;
+
+ case '_': /* `_' in number just ignored */
+ if (nondigit) goto decode_num;
+ nondigit = c;
+ break;
+
+ default:
+ goto decode_num;
}
+ c = nextc(p);
+ }
decode_num:
- pushback(p, c);
- if (nondigit) {
+ pushback(p, c);
+ if (nondigit) {
trailing_uc:
- yyerror_i(p, "trailing `%c' in number", nondigit);
+ yyerror_i(p, "trailing `%c' in number", nondigit);
+ }
+ tokfix(p);
+ if (is_float) {
+ double d;
+ char *endp;
+
+ errno = 0;
+ d = strtod(tok(p), &endp);
+ if (d == 0 && endp == tok(p)) {
+ yywarning_s(p, "corrupted float value %s", tok(p));
}
- tokfix(p);
- if (is_float) {
- double d;
- char *endp;
-
- errno = 0;
- d = strtod(tok(p), &endp);
- if (d == 0 && endp == tok(p)) {
- yywarning_s(p, "corrupted float value %s", tok(p));
- }
- else if (errno == ERANGE) {
- yywarning_s(p, "float %s out of range", tok(p));
- errno = 0;
- }
- yylval.nd = new_float(p, tok(p));
- return tFLOAT;
+ else if (errno == ERANGE) {
+ yywarning_s(p, "float %s out of range", tok(p));
+ errno = 0;
}
- yylval.nd = new_int(p, tok(p), 10);
- return tINTEGER;
+ yylval.nd = new_float(p, tok(p));
+ return tFLOAT;
}
+ yylval.nd = new_int(p, tok(p), 10);
+ return tINTEGER;
+ }
case ')':
case ']':
@@ -4513,8 +4730,8 @@ parser_yylex(parser_state *p)
c = nextc(p);
if (c == ':') {
if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) {
- p->lstate = EXPR_BEG;
- return tCOLON3;
+ p->lstate = EXPR_BEG;
+ return tCOLON3;
}
p->lstate = EXPR_DOT;
return tCOLON2;
@@ -4545,7 +4762,8 @@ parser_yylex(parser_state *p)
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
return '/';
@@ -4558,7 +4776,8 @@ parser_yylex(parser_state *p)
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
pushback(p, c);
@@ -4575,7 +4794,7 @@ parser_yylex(parser_state *p)
case '~':
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
if ((c = nextc(p)) != '@') {
- pushback(p, c);
+ pushback(p, c);
}
p->lstate = EXPR_ARG;
}
@@ -4602,11 +4821,11 @@ parser_yylex(parser_state *p)
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
if ((c = nextc(p)) == ']') {
- if ((c = nextc(p)) == '=') {
- return tASET;
- }
- pushback(p, c);
- return tAREF;
+ if ((c = nextc(p)) == '=') {
+ return tASET;
+ }
+ pushback(p, c);
+ return tAREF;
}
pushback(p, c);
return '[';
@@ -4659,21 +4878,21 @@ parser_yylex(parser_state *p)
int paren;
c = nextc(p);
- quotation:
- if (c == -1 || !ISALNUM(c)) {
- term = c;
- c = 'Q';
+ quotation:
+ if (c < 0 || !ISALNUM(c)) {
+ term = c;
+ c = 'Q';
}
else {
- term = nextc(p);
- if (isalnum(term)) {
- yyerror(p, "unknown type of %string");
- return 0;
- }
+ term = nextc(p);
+ if (isalnum(term)) {
+ yyerror(p, "unknown type of %string");
+ return 0;
+ }
}
- if (c == -1 || term == -1) {
- yyerror(p, "unterminated quoted string meets end of file");
- return 0;
+ if (c < 0 || term < 0) {
+ yyerror(p, "unterminated quoted string meets end of file");
+ return 0;
}
paren = term;
if (term == '(') term = ')';
@@ -4684,44 +4903,44 @@ parser_yylex(parser_state *p)
switch (c) {
case 'Q':
- p->lex_strterm = new_strterm(p, str_dquote, term, paren);
- return tSTRING_BEG;
+ p->lex_strterm = new_strterm(p, str_dquote, term, paren);
+ return tSTRING_BEG;
case 'q':
- p->lex_strterm = new_strterm(p, str_squote, term, paren);
- return parse_string(p);
+ p->lex_strterm = new_strterm(p, str_squote, term, paren);
+ return parse_string(p);
case 'W':
- p->lex_strterm = new_strterm(p, str_dword, term, paren);
- return tWORDS_BEG;
+ p->lex_strterm = new_strterm(p, str_dword, term, paren);
+ return tWORDS_BEG;
case 'w':
- p->lex_strterm = new_strterm(p, str_sword, term, paren);
- return tWORDS_BEG;
+ p->lex_strterm = new_strterm(p, str_sword, term, paren);
+ return tWORDS_BEG;
case 'x':
- p->lex_strterm = new_strterm(p, str_xquote, term, paren);
- return tXSTRING_BEG;
+ p->lex_strterm = new_strterm(p, str_xquote, term, paren);
+ return tXSTRING_BEG;
case 'r':
- p->lex_strterm = new_strterm(p, str_regexp, term, paren);
- return tREGEXP_BEG;
+ p->lex_strterm = new_strterm(p, str_regexp, term, paren);
+ return tREGEXP_BEG;
case 's':
- p->lex_strterm = new_strterm(p, str_ssym, term, paren);
- return tSYMBEG;
+ p->lex_strterm = new_strterm(p, str_ssym, term, paren);
+ return tSYMBEG;
case 'I':
- p->lex_strterm = new_strterm(p, str_dsymbols, term, paren);
- return tSYMBOLS_BEG;
+ p->lex_strterm = new_strterm(p, str_dsymbols, term, paren);
+ return tSYMBOLS_BEG;
case 'i':
- p->lex_strterm = new_strterm(p, str_ssymbols, term, paren);
- return tSYMBOLS_BEG;
+ p->lex_strterm = new_strterm(p, str_ssymbols, term, paren);
+ return tSYMBOLS_BEG;
default:
- yyerror(p, "unknown type of %string");
- return 0;
+ yyerror(p, "unknown type of %string");
+ return 0;
}
}
if ((c = nextc(p)) == '=') {
@@ -4734,7 +4953,8 @@ parser_yylex(parser_state *p)
}
if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
p->lstate = EXPR_ARG;
- } else {
+ }
+ else {
p->lstate = EXPR_BEG;
}
pushback(p, c);
@@ -4744,14 +4964,14 @@ parser_yylex(parser_state *p)
p->lstate = EXPR_END;
token_column = newtok(p);
c = nextc(p);
- if (c == -1) {
+ if (c < 0) {
yyerror(p, "incomplete global variable syntax");
return 0;
}
switch (c) {
case '_': /* $_: last read line string */
c = nextc(p);
- if (c != -1 && identchar(c)) { /* if there is more after _ it is a variable */
+ if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */
tokadd(p, '$');
tokadd(p, c);
break;
@@ -4778,7 +4998,7 @@ parser_yylex(parser_state *p)
tokadd(p, '$');
tokadd(p, c);
tokfix(p);
- yylval.id = intern(tok(p));
+ yylval.id = intern_cstr(tok(p));
return tGVAR;
case '-':
@@ -4786,9 +5006,9 @@ parser_yylex(parser_state *p)
tokadd(p, c);
c = nextc(p);
pushback(p, c);
- gvar:
+ gvar:
tokfix(p);
- yylval.id = intern(tok(p));
+ yylval.id = intern_cstr(tok(p));
return tGVAR;
case '&': /* $&: last match */
@@ -4796,9 +5016,9 @@ parser_yylex(parser_state *p)
case '\'': /* $': string after last match */
case '+': /* $+: string matches last pattern */
if (last_state == EXPR_FNAME) {
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
}
yylval.nd = new_back_ref(p, c);
return tBACK_REF;
@@ -4807,9 +5027,9 @@ parser_yylex(parser_state *p)
case '4': case '5': case '6':
case '7': case '8': case '9':
do {
- tokadd(p, c);
- c = nextc(p);
- } while (c != -1 && isdigit(c));
+ tokadd(p, c);
+ c = nextc(p);
+ } while (c >= 0 && isdigit(c));
pushback(p, c);
if (last_state == EXPR_FNAME) goto gvar;
tokfix(p);
@@ -4818,58 +5038,58 @@ parser_yylex(parser_state *p)
default:
if (!identchar(c)) {
- pushback(p, c);
- return '$';
+ pushback(p, c);
+ return '$';
}
case '0':
tokadd(p, '$');
}
break;
- case '@':
- c = nextc(p);
- token_column = newtok(p);
- tokadd(p, '@');
- if (c == '@') {
- tokadd(p, '@');
+ case '@':
c = nextc(p);
- }
- if (c == -1) {
- if (p->bidx == 1) {
- yyerror(p, "incomplete instance variable syntax");
+ token_column = newtok(p);
+ tokadd(p, '@');
+ if (c == '@') {
+ tokadd(p, '@');
+ c = nextc(p);
}
- else {
- yyerror(p, "incomplete class variable syntax");
+ if (c < 0) {
+ if (p->bidx == 1) {
+ yyerror(p, "incomplete instance variable syntax");
+ }
+ else {
+ yyerror(p, "incomplete class variable syntax");
+ }
+ return 0;
}
- return 0;
- }
- else if (isdigit(c)) {
- if (p->bidx == 1) {
- yyerror_i(p, "`@%c' is not allowed as an instance variable name", c);
+ else if (isdigit(c)) {
+ if (p->bidx == 1) {
+ yyerror_i(p, "`@%c' is not allowed as an instance variable name", c);
+ }
+ else {
+ yyerror_i(p, "`@@%c' is not allowed as a class variable name", c);
+ }
+ return 0;
}
- else {
- yyerror_i(p, "`@@%c' is not allowed as a class variable name", c);
+ if (!identchar(c)) {
+ pushback(p, c);
+ return '@';
}
- return 0;
- }
- if (!identchar(c)) {
- pushback(p, c);
- return '@';
- }
- break;
+ break;
- case '_':
- token_column = newtok(p);
- break;
+ case '_':
+ token_column = newtok(p);
+ break;
- default:
- if (!identchar(c)) {
- yyerror_i(p, "Invalid char `\\x%02X' in expression", c);
- goto retry;
- }
+ default:
+ if (!identchar(c)) {
+ yyerror_i(p, "Invalid char `\\x%02X' in expression", c);
+ goto retry;
+ }
- token_column = newtok(p);
- break;
+ token_column = newtok(p);
+ break;
}
do {
@@ -4906,104 +5126,104 @@ parser_yylex(parser_state *p)
case '@':
p->lstate = EXPR_END;
if (tok(p)[1] == '@')
- result = tCVAR;
+ result = tCVAR;
else
- result = tIVAR;
+ result = tIVAR;
break;
default:
if (toklast(p) == '!' || toklast(p) == '?') {
- result = tFID;
+ result = tFID;
}
else {
- if (p->lstate == EXPR_FNAME) {
- if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
- (!peek(p, '=') || (peek_n(p, '>', 1)))) {
- result = tIDENTIFIER;
- tokadd(p, c);
- tokfix(p);
- }
- else {
- pushback(p, c);
- }
- }
- if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) {
- result = tCONSTANT;
- }
- else {
- result = tIDENTIFIER;
- }
+ if (p->lstate == EXPR_FNAME) {
+ if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
+ (!peek(p, '=') || (peek_n(p, '>', 1)))) {
+ result = tIDENTIFIER;
+ tokadd(p, c);
+ tokfix(p);
+ }
+ else {
+ pushback(p, c);
+ }
+ }
+ if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) {
+ result = tCONSTANT;
+ }
+ else {
+ result = tIDENTIFIER;
+ }
}
if (IS_LABEL_POSSIBLE()) {
- if (IS_LABEL_SUFFIX(0)) {
- p->lstate = EXPR_BEG;
- nextc(p);
- tokfix(p);
- yylval.id = intern(tok(p));
- return tLABEL;
- }
+ if (IS_LABEL_SUFFIX(0)) {
+ p->lstate = EXPR_BEG;
+ nextc(p);
+ tokfix(p);
+ yylval.id = intern_cstr(tok(p));
+ return tLABEL;
+ }
}
if (p->lstate != EXPR_DOT) {
- const struct kwtable *kw;
-
- /* See if it is a reserved word. */
- kw = mrb_reserved_word(tok(p), toklen(p));
- if (kw) {
- enum mrb_lex_state_enum state = p->lstate;
- p->lstate = kw->state;
- if (state == EXPR_FNAME) {
- yylval.id = intern(kw->name);
- return kw->id[0];
- }
- if (p->lstate == EXPR_BEG) {
- p->cmd_start = TRUE;
- }
- if (kw->id[0] == keyword_do) {
- if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
- p->lpar_beg = 0;
- p->paren_nest--;
- return keyword_do_LAMBDA;
- }
- if (COND_P()) return keyword_do_cond;
- if (CMDARG_P() && state != EXPR_CMDARG)
- return keyword_do_block;
- if (state == EXPR_ENDARG || state == EXPR_BEG)
- return keyword_do_block;
- return keyword_do;
- }
- if (state == EXPR_BEG || state == EXPR_VALUE)
- return kw->id[0];
- else {
- if (kw->id[0] != kw->id[1])
- p->lstate = EXPR_BEG;
- return kw->id[1];
- }
- }
+ const struct kwtable *kw;
+
+ /* See if it is a reserved word. */
+ kw = mrb_reserved_word(tok(p), toklen(p));
+ if (kw) {
+ enum mrb_lex_state_enum state = p->lstate;
+ p->lstate = kw->state;
+ if (state == EXPR_FNAME) {
+ yylval.id = intern_cstr(kw->name);
+ return kw->id[0];
+ }
+ if (p->lstate == EXPR_BEG) {
+ p->cmd_start = TRUE;
+ }
+ if (kw->id[0] == keyword_do) {
+ if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
+ p->lpar_beg = 0;
+ p->paren_nest--;
+ return keyword_do_LAMBDA;
+ }
+ if (COND_P()) return keyword_do_cond;
+ if (CMDARG_P() && state != EXPR_CMDARG)
+ return keyword_do_block;
+ if (state == EXPR_ENDARG || state == EXPR_BEG)
+ return keyword_do_block;
+ return keyword_do;
+ }
+ if (state == EXPR_BEG || state == EXPR_VALUE)
+ return kw->id[0];
+ else {
+ if (kw->id[0] != kw->id[1])
+ p->lstate = EXPR_BEG;
+ return kw->id[1];
+ }
+ }
}
if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) {
- if (cmd_state) {
- p->lstate = EXPR_CMDARG;
- }
- else {
- p->lstate = EXPR_ARG;
- }
+ if (cmd_state) {
+ p->lstate = EXPR_CMDARG;
+ }
+ else {
+ p->lstate = EXPR_ARG;
+ }
}
else if (p->lstate == EXPR_FNAME) {
- p->lstate = EXPR_ENDFN;
+ p->lstate = EXPR_ENDFN;
}
else {
- p->lstate = EXPR_END;
+ p->lstate = EXPR_END;
}
}
{
- mrb_sym ident = intern(tok(p));
+ mrb_sym ident = intern_cstr(tok(p));
yylval.id = ident;
#if 0
if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
- p->lstate = EXPR_END;
+ p->lstate = EXPR_END;
}
#endif
}
@@ -5027,7 +5247,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt)
{
if (!cxt) return;
if (cxt->lineno) p->lineno = cxt->lineno;
- if (cxt->filename) p->filename = cxt->filename;
+ if (cxt->filename) mrb_parser_set_filename(p, cxt->filename);
if (cxt->syms) {
int i;
@@ -5062,21 +5282,19 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt)
}
}
-void codedump_all(mrb_state*, int);
-void parser_dump(mrb_state *mrb, node *tree, int offset);
+void mrb_codedump_all(mrb_state*, struct RProc*);
+void mrb_parser_dump(mrb_state *mrb, node *tree, int offset);
void
mrb_parser_parse(parser_state *p, mrbc_context *c)
{
- if (setjmp(p->jmp) != 0) {
- yyerror(p, "memory allocation error");
- p->nerr++;
- p->tree = 0;
- return;
- }
+ struct mrb_jmpbuf buf;
+ p->jmp = &buf;
+
+ MRB_TRY(p->jmp) {
p->cmd_start = TRUE;
- p->in_def = p->in_single = FALSE;
+ p->in_def = p->in_single = 0;
p->nerr = p->nwarn = 0;
p->lex_strterm = NULL;
@@ -5087,8 +5305,17 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
}
parser_update_cxt(p, c);
if (c && c->dump_result) {
- parser_dump(p->mrb, p->tree, 0);
+ mrb_parser_dump(p->mrb, p->tree, 0);
+ }
+
}
+ MRB_CATCH(p->jmp) {
+ yyerror(p, "memory allocation error");
+ p->nerr++;
+ p->tree = 0;
+ return;
+ }
+ MRB_END_EXC(p->jmp);
}
parser_state*
@@ -5106,7 +5333,6 @@ mrb_parser_new(mrb_state *mrb)
*p = parser_state_zero;
p->mrb = mrb;
p->pool = pool;
- p->in_def = p->in_single = 0;
p->s = p->send = NULL;
#ifdef ENABLE_STDIO
@@ -5114,9 +5340,9 @@ mrb_parser_new(mrb_state *mrb)
#endif
p->cmd_start = TRUE;
- p->in_def = p->in_single = FALSE;
+ p->in_def = p->in_single = 0;
- p->capture_errors = 0;
+ p->capture_errors = FALSE;
p->lineno = 1;
p->column = 0;
#if defined(PARSER_TEST) || defined(PARSER_DEBUG)
@@ -5124,7 +5350,12 @@ mrb_parser_new(mrb_state *mrb)
#endif
p->lex_strterm = NULL;
- p->heredocs = p->parsing_heredoc = NULL;
+ p->all_heredocs = p->parsing_heredoc = NULL;
+ p->lex_strterm_before_heredoc = NULL;
+
+ p->current_filename_index = -1;
+ p->filename_table = NULL;
+ p->filename_table_length = 0;
return p;
}
@@ -5159,7 +5390,6 @@ mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s)
memcpy(p, s, len + 1);
c->filename = p;
- c->lineno = 1;
}
return c->filename;
}
@@ -5171,6 +5401,41 @@ mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser
c->partial_data = data;
}
+void
+mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
+{
+ mrb_sym sym;
+ size_t i;
+ mrb_sym* new_table;
+
+ sym = mrb_intern_cstr(p->mrb, f);
+ p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
+ p->lineno = (p->filename_table_length > 0)? 0 : 1;
+
+ for (i = 0; i < p->filename_table_length; ++i) {
+ if (p->filename_table[i] == sym) {
+ p->current_filename_index = i;
+ return;
+ }
+ }
+
+ p->current_filename_index = p->filename_table_length++;
+
+ new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
+ if (p->filename_table) {
+ memcpy(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
+ }
+ p->filename_table = new_table;
+ p->filename_table[p->filename_table_length - 1] = sym;
+}
+
+char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
+ if (idx >= p->filename_table_length) { return NULL; }
+ else {
+ return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
+ }
+}
+
#ifdef ENABLE_STDIO
parser_state*
mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
@@ -5212,7 +5477,6 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
{
struct RClass *target = mrb->object_class;
struct RProc *proc;
- int n;
mrb_value v;
if (!p) {
@@ -5221,40 +5485,38 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
if (!p->tree || p->nerr) {
if (p->capture_errors) {
char buf[256];
+ int n;
n = snprintf(buf, sizeof(buf), "line %d: %s\n",
- p->error_buffer[0].lineno, p->error_buffer[0].message);
+ p->error_buffer[0].lineno, p->error_buffer[0].message);
mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
mrb_parser_free(p);
return mrb_undef_value();
}
else {
- static const char msg[] = "syntax error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, msg, sizeof(msg) - 1));
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
mrb_parser_free(p);
return mrb_undef_value();
}
}
- n = mrb_generate_code(mrb, p);
+ proc = mrb_generate_code(mrb, p);
mrb_parser_free(p);
- if (n < 0) {
- static const char msg[] = "codegen error";
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SCRIPT_ERROR, msg, sizeof(msg) - 1));
- return mrb_nil_value();
+ if (proc == NULL) {
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
+ return mrb_undef_value();
}
if (c) {
- if (c->dump_result) codedump_all(mrb, n);
- if (c->no_exec) return mrb_fixnum_value(n);
+ if (c->dump_result) mrb_codedump_all(mrb, proc);
+ if (c->no_exec) return mrb_obj_value(proc);
if (c->target_class) {
target = c->target_class;
}
}
- proc = mrb_proc_new(mrb, mrb->irep[n]);
proc->target_class = target;
if (mrb->c->ci) {
mrb->c->ci->target_class = target;
}
- v = mrb_run(mrb, proc, mrb_top_self(mrb));
+ v = mrb_toplevel_run(mrb, proc);
if (mrb->exc) return mrb_nil_value();
return v;
}
@@ -5312,7 +5574,7 @@ static void
dump_recur(mrb_state *mrb, node *tree, int offset)
{
while (tree) {
- parser_dump(mrb, tree->car, offset);
+ mrb_parser_dump(mrb, tree->car, offset);
tree = tree->cdr;
}
}
@@ -5320,13 +5582,13 @@ dump_recur(mrb_state *mrb, node *tree, int offset)
#endif
void
-parser_dump(mrb_state *mrb, node *tree, int offset)
+mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
{
#ifdef ENABLE_STDIO
int n;
if (!tree) return;
- again:
+ again:
dump_prefix(offset);
n = (int)(intptr_t)tree->car;
tree = tree->cdr;
@@ -5341,7 +5603,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
if (tree->car) {
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
}
tree = tree->cdr;
if (tree->car) {
@@ -5350,30 +5612,30 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
dump_prefix(offset+1);
printf("rescue:\n");
while (n2) {
- node *n3 = n2->car;
- if (n3->car) {
- dump_prefix(offset+2);
- printf("handle classes:\n");
- dump_recur(mrb, n3->car, offset+3);
- }
- if (n3->cdr->car) {
- dump_prefix(offset+2);
- printf("exc_var:\n");
- parser_dump(mrb, n3->cdr->car, offset+3);
- }
- if (n3->cdr->cdr->car) {
- dump_prefix(offset+2);
- printf("rescue body:\n");
- parser_dump(mrb, n3->cdr->cdr->car, offset+3);
- }
- n2 = n2->cdr;
+ node *n3 = n2->car;
+ if (n3->car) {
+ dump_prefix(offset+2);
+ printf("handle classes:\n");
+ dump_recur(mrb, n3->car, offset+3);
+ }
+ if (n3->cdr->car) {
+ dump_prefix(offset+2);
+ printf("exc_var:\n");
+ mrb_parser_dump(mrb, n3->cdr->car, offset+3);
+ }
+ if (n3->cdr->cdr->car) {
+ dump_prefix(offset+2);
+ printf("rescue body:\n");
+ mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3);
+ }
+ n2 = n2->cdr;
}
}
tree = tree->cdr;
if (tree->car) {
dump_prefix(offset+1);
printf("else:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
}
break;
@@ -5381,10 +5643,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_ENSURE:\n");
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(offset+1);
printf("ensure:\n");
- parser_dump(mrb, tree->cdr->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->cdr, offset+2);
break;
case NODE_LAMBDA:
@@ -5392,85 +5654,85 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
goto block;
case NODE_BLOCK:
- block:
+ block:
printf("NODE_BLOCK:\n");
- tree = tree->cdr;
- if (tree->car) {
- node *n = tree->car;
+ tree = tree->cdr;
+ if (tree->car) {
+ node *n = tree->car;
- if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
+ if (n->car) {
+ dump_prefix(offset+1);
+ printf("mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
+ }
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(offset+1);
+ printf("optional args:\n");
+ {
+ node *n2 = n->car;
+
+ while (n2) {
+ dump_prefix(offset+2);
+ printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
+ mrb_parser_dump(mrb, n2->car->cdr, 0);
+ n2 = n2->cdr;
+ }
}
}
- dump_prefix(offset+1);
- printf("body:\n");
- parser_dump(mrb, tree->cdr->car, offset+2);
- break;
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(offset+1);
+ printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
+ }
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(offset+1);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
+ }
+ n = n->cdr;
+ if (n) {
+ dump_prefix(offset+1);
+ printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
+ }
+ }
+ dump_prefix(offset+1);
+ printf("body:\n");
+ mrb_parser_dump(mrb, tree->cdr->car, offset+2);
+ break;
case NODE_IF:
printf("NODE_IF:\n");
dump_prefix(offset+1);
printf("cond:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(offset+1);
printf("then:\n");
- parser_dump(mrb, tree->cdr->car, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->car, offset+2);
if (tree->cdr->cdr->car) {
dump_prefix(offset+1);
printf("else:\n");
- parser_dump(mrb, tree->cdr->cdr->car, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2);
}
break;
case NODE_AND:
printf("NODE_AND:\n");
- parser_dump(mrb, tree->car, offset+1);
- parser_dump(mrb, tree->cdr, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->cdr, offset+1);
break;
case NODE_OR:
printf("NODE_OR:\n");
- parser_dump(mrb, tree->car, offset+1);
- parser_dump(mrb, tree->cdr, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->cdr, offset+1);
break;
case NODE_CASE:
printf("NODE_CASE:\n");
if (tree->car) {
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
}
tree = tree->cdr;
while (tree) {
@@ -5479,7 +5741,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
dump_recur(mrb, tree->car->car, offset+2);
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->car->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->car->cdr, offset+2);
tree = tree->cdr;
}
break;
@@ -5488,20 +5750,20 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_WHILE:\n");
dump_prefix(offset+1);
printf("cond:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_UNTIL:
printf("NODE_UNTIL:\n");
dump_prefix(offset+1);
printf("cond:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_FOR:
@@ -5512,35 +5774,35 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n2 = tree->car;
if (n2->car) {
- dump_prefix(offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
+ dump_prefix(offset+2);
+ printf("pre:\n");
+ dump_recur(mrb, n2->car, offset+3);
}
n2 = n2->cdr;
if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("rest:\n");
- parser_dump(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- }
+ if (n2->car) {
+ dump_prefix(offset+2);
+ printf("rest:\n");
+ mrb_parser_dump(mrb, n2->car, offset+3);
+ }
+ n2 = n2->cdr;
+ if (n2) {
+ if (n2->car) {
+ dump_prefix(offset+2);
+ printf("post:\n");
+ dump_recur(mrb, n2->car, offset+3);
+ }
+ }
}
}
tree = tree->cdr;
dump_prefix(offset+1);
printf("in:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
tree = tree->cdr;
dump_prefix(offset+1);
printf("do:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
break;
case NODE_SCOPE:
@@ -5549,17 +5811,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n2 = tree->car;
if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(offset+1);
- printf("local variables:\n");
- dump_prefix(offset+2);
- while (n2) {
- if (n2->car) {
- if (n2 != tree->car) printf(", ");
- printf("%s", mrb_sym2name(mrb, sym(n2->car)));
- }
- n2 = n2->cdr;
- }
- printf("\n");
+ dump_prefix(offset+1);
+ printf("local variables:\n");
+ dump_prefix(offset+2);
+ while (n2) {
+ if (n2->car) {
+ if (n2 != tree->car) printf(", ");
+ printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+ }
+ n2 = n2->cdr;
+ }
+ printf("\n");
}
}
tree = tree->cdr;
@@ -5569,39 +5831,39 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_FCALL:
case NODE_CALL:
printf("NODE_CALL:\n");
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(offset+1);
printf("method='%s' (%d)\n",
- mrb_sym2name(mrb, sym(tree->cdr->car)),
- (int)(intptr_t)tree->cdr->car);
+ mrb_sym2name(mrb, sym(tree->cdr->car)),
+ (int)(intptr_t)tree->cdr->car);
tree = tree->cdr->cdr->car;
if (tree) {
dump_prefix(offset+1);
printf("args:\n");
dump_recur(mrb, tree->car, offset+2);
if (tree->cdr) {
- dump_prefix(offset+1);
- printf("block:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ dump_prefix(offset+1);
+ printf("block:\n");
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
}
}
break;
case NODE_DOT2:
printf("NODE_DOT2:\n");
- parser_dump(mrb, tree->car, offset+1);
- parser_dump(mrb, tree->cdr, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->cdr, offset+1);
break;
case NODE_DOT3:
printf("NODE_DOT3:\n");
- parser_dump(mrb, tree->car, offset+1);
- parser_dump(mrb, tree->cdr, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->cdr, offset+1);
break;
case NODE_COLON2:
printf("NODE_COLON2:\n");
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(offset+1);
printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr)));
break;
@@ -5622,27 +5884,27 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
while (tree) {
dump_prefix(offset+1);
printf("key:\n");
- parser_dump(mrb, tree->car->car, offset+2);
+ mrb_parser_dump(mrb, tree->car->car, offset+2);
dump_prefix(offset+1);
printf("value:\n");
- parser_dump(mrb, tree->car->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->car->cdr, offset+2);
tree = tree->cdr;
}
break;
case NODE_SPLAT:
printf("NODE_SPLAT:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_ASGN:
printf("NODE_ASGN:\n");
dump_prefix(offset+1);
printf("lhs:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
dump_prefix(offset+1);
printf("rhs:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_MASGN:
@@ -5653,48 +5915,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n2 = tree->car;
if (n2->car) {
- dump_prefix(offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
+ dump_prefix(offset+2);
+ printf("pre:\n");
+ dump_recur(mrb, n2->car, offset+3);
}
n2 = n2->cdr;
if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("rest:\n");
- if (n2->car == (node*)-1) {
- dump_prefix(offset+2);
- printf("(empty)\n");
- }
- else {
- parser_dump(mrb, n2->car, offset+3);
- }
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- }
+ if (n2->car) {
+ dump_prefix(offset+2);
+ printf("rest:\n");
+ if (n2->car == (node*)-1) {
+ dump_prefix(offset+2);
+ printf("(empty)\n");
+ }
+ else {
+ mrb_parser_dump(mrb, n2->car, offset+3);
+ }
+ }
+ n2 = n2->cdr;
+ if (n2) {
+ if (n2->car) {
+ dump_prefix(offset+2);
+ printf("post:\n");
+ dump_recur(mrb, n2->car, offset+3);
+ }
+ }
}
}
dump_prefix(offset+1);
printf("rhs:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
break;
case NODE_OP_ASGN:
printf("NODE_OP_ASGN:\n");
dump_prefix(offset+1);
printf("lhs:\n");
- parser_dump(mrb, tree->car, offset+2);
+ mrb_parser_dump(mrb, tree->car, offset+2);
tree = tree->cdr;
dump_prefix(offset+1);
printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
tree = tree->cdr;
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
break;
case NODE_SUPER:
@@ -5704,9 +5966,9 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("args:\n");
dump_recur(mrb, tree->car, offset+2);
if (tree->cdr) {
- dump_prefix(offset+1);
- printf("block:\n");
- parser_dump(mrb, tree->cdr, offset+2);
+ dump_prefix(offset+1);
+ printf("block:\n");
+ mrb_parser_dump(mrb, tree->cdr, offset+2);
}
}
break;
@@ -5717,7 +5979,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_RETURN:
printf("NODE_RETURN:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_YIELD:
@@ -5727,12 +5989,12 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_BREAK:
printf("NODE_BREAK:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_NEXT:
printf("NODE_NEXT:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_REDO:
@@ -5767,10 +6029,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_MATCH:\n");
dump_prefix(offset + 1);
printf("lhs:\n");
- parser_dump(mrb, tree->car, offset + 2);
+ mrb_parser_dump(mrb, tree->car, offset + 2);
dump_prefix(offset + 1);
printf("rhs:\n");
- parser_dump(mrb, tree->cdr, offset + 2);
+ mrb_parser_dump(mrb, tree->cdr, offset + 2);
break;
case NODE_BACK_REF:
@@ -5787,7 +6049,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_BLOCK_ARG:
printf("NODE_BLOCK_ARG:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_INT:
@@ -5800,7 +6062,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_NEGATE:
printf("NODE_NEGATE\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_STR:
@@ -5856,8 +6118,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_ALIAS:
printf("NODE_ALIAS %s %s:\n",
- mrb_sym2name(mrb, sym(tree->car)),
- mrb_sym2name(mrb, sym(tree->cdr)));
+ mrb_sym2name(mrb, sym(tree->car)),
+ mrb_sym2name(mrb, sym(tree->cdr)));
break;
case NODE_UNDEF:
@@ -5865,8 +6127,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
{
node *t = tree;
while (t) {
- printf(" %s", mrb_sym2name(mrb, sym(t->car)));
- t = t->cdr;
+ printf(" %s", mrb_sym2name(mrb, sym(t->car)));
+ t = t->cdr;
}
}
printf(":\n");
@@ -5883,18 +6145,18 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
}
else {
- parser_dump(mrb, tree->car->car, offset+1);
+ mrb_parser_dump(mrb, tree->car->car, offset+1);
dump_prefix(offset+1);
printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
}
if (tree->cdr->car) {
dump_prefix(offset+1);
printf("super:\n");
- parser_dump(mrb, tree->cdr->car, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->car, offset+2);
}
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2);
break;
case NODE_MODULE:
@@ -5908,21 +6170,21 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
}
else {
- parser_dump(mrb, tree->car->car, offset+1);
+ mrb_parser_dump(mrb, tree->car->car, offset+1);
dump_prefix(offset+1);
printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
}
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->cdr->car->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
break;
case NODE_SCLASS:
printf("NODE_SCLASS:\n");
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(offset+1);
printf("body:\n");
- parser_dump(mrb, tree->cdr->car->cdr, offset+2);
+ mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
break;
case NODE_DEF:
@@ -5934,17 +6196,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n2 = tree->car;
if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(offset+1);
- printf("local variables:\n");
- dump_prefix(offset+2);
- while (n2) {
- if (n2->car) {
- if (n2 != tree->car) printf(", ");
- printf("%s", mrb_sym2name(mrb, sym(n2->car)));
- }
- n2 = n2->cdr;
- }
- printf("\n");
+ dump_prefix(offset+1);
+ printf("local variables:\n");
+ dump_prefix(offset+2);
+ while (n2) {
+ if (n2->car) {
+ if (n2 != tree->car) printf(", ");
+ printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+ }
+ n2 = n2->cdr;
+ }
+ printf("\n");
}
}
tree = tree->cdr;
@@ -5952,48 +6214,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n = tree->car;
if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
+ dump_prefix(offset+1);
+ printf("mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
+ dump_prefix(offset+1);
+ printf("optional args:\n");
+ {
+ node *n2 = n->car;
+
+ while (n2) {
+ dump_prefix(offset+2);
+ printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
+ mrb_parser_dump(mrb, n2->car->cdr, 0);
+ n2 = n2->cdr;
+ }
+ }
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
+ dump_prefix(offset+1);
+ printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
+ dump_prefix(offset+1);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
}
n = n->cdr;
if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
+ dump_prefix(offset+1);
+ printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
}
}
- parser_dump(mrb, tree->cdr->car, offset+1);
+ mrb_parser_dump(mrb, tree->cdr->car, offset+1);
break;
case NODE_SDEF:
printf("NODE_SDEF:\n");
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
tree = tree->cdr;
dump_prefix(offset+1);
printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
@@ -6002,54 +6264,54 @@ parser_dump(mrb_state *mrb, node *tree, int offset)
node *n = tree->car;
if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
+ dump_prefix(offset+1);
+ printf("mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
+ dump_prefix(offset+1);
+ printf("optional args:\n");
+ {
+ node *n2 = n->car;
+
+ while (n2) {
+ dump_prefix(offset+2);
+ printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
+ mrb_parser_dump(mrb, n2->car->cdr, 0);
+ n2 = n2->cdr;
+ }
+ }
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
+ dump_prefix(offset+1);
+ printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
}
n = n->cdr;
if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
+ dump_prefix(offset+1);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
}
n = n->cdr;
if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
+ dump_prefix(offset+1);
+ printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
}
}
tree = tree->cdr;
- parser_dump(mrb, tree->car, offset+1);
+ mrb_parser_dump(mrb, tree->car, offset+1);
break;
case NODE_POSTEXE:
printf("NODE_POSTEXE:\n");
- parser_dump(mrb, tree, offset+1);
+ mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_HEREDOC:
printf("NODE_HEREDOC:\n");
- parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
+ mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break;
default:
diff --git a/src/pool.c b/src/pool.c
index f09df92c5..4d8c42dd1 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -5,6 +5,7 @@
*/
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include "mruby.h"
@@ -36,12 +37,12 @@ struct mrb_pool {
#undef TEST_POOL
#ifdef TEST_POOL
-#define mrb_malloc(m,s) malloc(s)
+#define mrb_malloc_simple(m,s) malloc(s)
#define mrb_free(m,p) free(p)
#endif
#ifdef POOL_ALIGNMENT
-# define ALIGN_PADDING(x) ((-x) & (POOL_ALIGNMENT - 1))
+# define ALIGN_PADDING(x) ((SIZE_MAX - (x) + 1) & (POOL_ALIGNMENT - 1))
#else
# define ALIGN_PADDING(x) (0)
#endif
@@ -49,7 +50,7 @@ struct mrb_pool {
mrb_pool*
mrb_pool_open(mrb_state *mrb)
{
- mrb_pool *pool = (mrb_pool *)mrb_malloc(mrb, sizeof(mrb_pool));
+ mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool));
if (pool) {
pool->mrb = mrb;
@@ -81,7 +82,7 @@ page_alloc(mrb_pool *pool, size_t len)
if (len < POOL_PAGE_SIZE)
len = POOL_PAGE_SIZE;
- page = (struct mrb_pool_page *)mrb_malloc(pool->mrb, sizeof(struct mrb_pool_page)+len);
+ page = (struct mrb_pool_page *)mrb_malloc_simple(pool->mrb, sizeof(struct mrb_pool_page)+len);
if (page) {
page->offset = 0;
page->len = len;
diff --git a/src/print.c b/src/print.c
index 01c9b3cd0..6472a4675 100644
--- a/src/print.c
+++ b/src/print.c
@@ -6,19 +6,18 @@
#include "mruby.h"
#include "mruby/string.h"
+#include "mruby/variable.h"
static void
printstr(mrb_state *mrb, mrb_value obj)
{
#ifdef ENABLE_STDIO
- struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
- str = mrb_str_ptr(obj);
- s = str->ptr;
- len = str->len;
+ s = RSTRING_PTR(obj);
+ len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
#endif
@@ -43,8 +42,7 @@ mrb_print_error(mrb_state *mrb)
mrb_print_backtrace(mrb);
s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
if (mrb_string_p(s)) {
- struct RString *str = mrb_str_ptr(s);
- fwrite(str->ptr, str->len, 1, stderr);
+ fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr);
putc('\n', stderr);
}
#endif
@@ -53,19 +51,19 @@ mrb_print_error(mrb_state *mrb)
void
mrb_show_version(mrb_state *mrb)
{
- static const char version_msg[] = "mruby - Embeddable Ruby Copyright (c) 2010-2013 mruby developers\n";
mrb_value msg;
- msg = mrb_str_new(mrb, version_msg, sizeof(version_msg) - 1);
+ msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION"));
printstr(mrb, msg);
+ printstr(mrb, mrb_str_new_lit(mrb, "\n"));
}
void
mrb_show_copyright(mrb_state *mrb)
{
- static const char copyright_msg[] = "mruby - Copyright (c) 2010-2013 mruby developers\n";
mrb_value msg;
- msg = mrb_str_new(mrb, copyright_msg, sizeof(copyright_msg) - 1);
+ msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT"));
printstr(mrb, msg);
+ printstr(mrb, mrb_str_new_lit(mrb, "\n"));
}
diff --git a/src/proc.c b/src/proc.c
index 787a46492..fa4c28fc8 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -17,11 +17,19 @@ struct RProc *
mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
{
struct RProc *p;
+ mrb_callinfo *ci = mrb->c->ci;
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
- p->target_class = (mrb->c->ci) ? mrb->c->ci->target_class : 0;
+ p->target_class = 0;
+ if (ci) {
+ if (ci->proc)
+ p->target_class = ci->proc->target_class;
+ if (!p->target_class)
+ p->target_class = ci->target_class;
+ }
p->body.irep = irep;
p->env = 0;
+ mrb_irep_incref(mrb, irep);
return p;
}
@@ -33,7 +41,7 @@ closure_setup(mrb_state *mrb, struct RProc *p, int nlocals)
if (!mrb->c->ci->env) {
e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
- e->flags= (unsigned int)nlocals;
+ MRB_ENV_STACK_LEN(e)= (unsigned int)nlocals;
e->mid = mrb->c->ci->mid;
e->cioff = mrb->c->ci - mrb->c->cibase;
e->stack = mrb->c->stack;
@@ -62,6 +70,7 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
p->body.func = func;
p->flags |= MRB_PROC_CFUNC;
+ p->env = 0;
return p;
}
@@ -80,6 +89,9 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
{
a->flags = b->flags;
a->body = b->body;
+ if (!MRB_PROC_CFUNC_P(a)) {
+ a->body.irep->refcnt++;
+ };
a->target_class = b->target_class;
a->env = b->env;
}
@@ -181,15 +193,11 @@ void
mrb_init_proc(mrb_state *mrb)
{
struct RProc *m;
- mrb_irep *call_irep = (mrb_irep *)mrb_alloca(mrb, sizeof(mrb_irep));
+ mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
static const mrb_irep mrb_irep_zero = { 0 };
- if ( call_iseq == NULL || call_irep == NULL )
- return;
-
*call_irep = mrb_irep_zero;
call_irep->flags = MRB_ISEQ_NO_FREE;
- call_irep->idx = -1;
call_irep->iseq = call_iseq;
call_irep->ilen = 1;
@@ -201,8 +209,8 @@ mrb_init_proc(mrb_state *mrb)
mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
m = mrb_proc_new(mrb, call_irep);
- mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern2(mrb, "call", 4), m);
- mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern2(mrb, "[]", 2), m);
+ mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m);
+ mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m);
mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */
mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */
diff --git a/src/range.c b/src/range.c
index 1d6519a6e..6b1f7faa2 100644
--- a/src/range.c
+++ b/src/range.c
@@ -176,7 +176,7 @@ r_le(mrb_state *mrb, mrb_value a, mrb_value b)
mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
/* output :a < b => -1, a = b => 0, a > b => +1 */
- if (mrb_type(r) == MRB_TT_FIXNUM) {
+ if (mrb_fixnum_p(r)) {
mrb_int c = mrb_fixnum(r);
if (c == 0 || c == -1) return TRUE;
}
@@ -190,11 +190,7 @@ r_gt(mrb_state *mrb, mrb_value a, mrb_value b)
mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
/* output :a < b => -1, a = b => 0, a > b => +1 */
- if (mrb_type(r) == MRB_TT_FIXNUM) {
- if (mrb_fixnum(r) == 1) return TRUE;
- }
-
- return FALSE;
+ return mrb_fixnum_p(r) && mrb_fixnum(r) == 1;
}
static mrb_bool
@@ -203,7 +199,7 @@ r_ge(mrb_state *mrb, mrb_value a, mrb_value b)
mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
/* output :a < b => -1, a = b => 0, a > b => +1 */
- if (mrb_type(r) == MRB_TT_FIXNUM) {
+ if (mrb_fixnum_p(r)) {
mrb_int c = mrb_fixnum(r);
if (c == 0 || c == 1) return TRUE;
}
@@ -261,7 +257,7 @@ mrb_range_each(mrb_state *mrb, mrb_value range)
return range;
}
-mrb_int
+mrb_bool
mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len)
{
mrb_int beg, end, b, e;
@@ -315,29 +311,6 @@ range_to_s(mrb_state *mrb, mrb_value range)
return str;
}
-static mrb_value
-inspect_range(mrb_state *mrb, mrb_value range, int recur)
-{
- mrb_value str, str2;
- struct RRange *r = mrb_range_ptr(range);
-
- if (recur) {
- static const char s[2][14] = { "(... ... ...)", "(... .. ...)" };
- static const int n[] = { 13, 12 };
- int idx;
-
- idx = (r->excl) ? 0 : 1;
- return mrb_str_new(mrb, s[idx], n[idx]);
- }
- str = mrb_inspect(mrb, r->edges->beg);
- str2 = mrb_inspect(mrb, r->edges->end);
- str = mrb_str_dup(mrb, str);
- mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
- mrb_str_append(mrb, str, str2);
-
- return str;
-}
-
/* 15.2.14.4.13(x) */
/*
* call-seq:
@@ -351,7 +324,16 @@ inspect_range(mrb_state *mrb, mrb_value range, int recur)
static mrb_value
range_inspect(mrb_state *mrb, mrb_value range)
{
- return inspect_range(mrb, range, 0);
+ mrb_value str, str2;
+ struct RRange *r = mrb_range_ptr(range);
+
+ str = mrb_inspect(mrb, r->edges->beg);
+ str2 = mrb_inspect(mrb, r->edges->end);
+ str = mrb_str_dup(mrb, str);
+ mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
+ mrb_str_append(mrb, str, str2);
+
+ return str;
}
/* 15.2.14.4.14(x) */
@@ -394,7 +376,7 @@ range_eql(mrb_state *mrb, mrb_value range)
}
/* 15.2.14.4.15(x) */
-mrb_value
+static mrb_value
range_initialize_copy(mrb_state *mrb, mrb_value copy)
{
mrb_value src;
@@ -421,8 +403,6 @@ mrb_init_range(mrb_state *mrb)
r = mrb_define_class(mrb, "Range", mrb->object_class); /* 15.2.14 */
MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE);
- mrb_include_module(mrb, r, mrb_class_get(mrb, "Enumerable"));
-
mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */
mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */
mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */
diff --git a/src/re.h b/src/re.h
index 20cd0b226..ee2638b22 100644
--- a/src/re.h
+++ b/src/re.h
@@ -8,6 +8,5 @@
#define RE_H
#define REGEXP_CLASS "Regexp"
-#define REGEXP_CLASS_CSTR_LEN 6
-#endif
+#endif /* RE_H */
diff --git a/src/state.c b/src/state.c
index 5dcc4a40a..618b77cdd 100644
--- a/src/state.c
+++ b/src/state.c
@@ -7,9 +7,10 @@
#include <stdlib.h>
#include <string.h>
#include "mruby.h"
-#include "mruby/class.h"
#include "mruby/irep.h"
#include "mruby/variable.h"
+#include "mruby/debug.h"
+#include "mruby/string.h"
void mrb_init_heap(mrb_state*);
void mrb_init_core(mrb_state*);
@@ -18,7 +19,7 @@ void mrb_final_core(mrb_state*);
static mrb_value
inspect_main(mrb_state *mrb, mrb_value mod)
{
- return mrb_str_new(mrb, "main", 4);
+ return mrb_str_new_lit(mrb, "main");
}
mrb_state*
@@ -40,6 +41,11 @@ mrb_open_allocf(mrb_allocf f, void *ud)
mrb->allocf = f;
mrb->current_white_part = MRB_GC_WHITE_A;
+#ifndef MRB_GC_FIXED_ARENA
+ mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
+ mrb->arena_capa = MRB_GC_ARENA_SIZE;
+#endif
+
mrb_init_heap(mrb);
mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
*mrb->c = mrb_context_zero;
@@ -72,7 +78,6 @@ mrb_alloca(mrb_state *mrb, size_t size)
struct alloca_header *p;
p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size);
- if (p == NULL) return NULL;
p->next = mrb->mems;
mrb->mems = p;
return (void*)p->buf;
@@ -106,17 +111,101 @@ void mrb_free_symtbl(mrb_state *mrb);
void mrb_free_heap(mrb_state *mrb);
void
-mrb_irep_free(mrb_state *mrb, struct mrb_irep *irep)
+mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
+{
+ irep->refcnt++;
+}
+
+void
+mrb_irep_decref(mrb_state *mrb, mrb_irep *irep)
+{
+ irep->refcnt--;
+ if (irep->refcnt == 0) {
+ mrb_irep_free(mrb, irep);
+ }
+}
+
+void
+mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
{
+ size_t i;
+
if (!(irep->flags & MRB_ISEQ_NO_FREE))
mrb_free(mrb, irep->iseq);
+ 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]));
+ mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
+ }
+#ifdef MRB_WORD_BOXING
+ else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) {
+ mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
+ }
+#endif
+ }
mrb_free(mrb, irep->pool);
mrb_free(mrb, irep->syms);
+ for (i=0; i<irep->rlen; i++) {
+ mrb_irep_decref(mrb, irep->reps[i]);
+ }
+ mrb_free(mrb, irep->reps);
mrb_free(mrb, (void *)irep->filename);
mrb_free(mrb, irep->lines);
+ mrb_debug_info_free(mrb, irep->debug_info);
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 (s->flags & MRB_STR_NOFREE) {
+ 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 (s->flags & MRB_STR_EMBED) {
+ ptr = s->as.ary;
+ len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT);
+ }
+ else {
+ ptr = s->as.heap.ptr;
+ len = s->as.heap.len;
+ }
+
+ if (len < RSTRING_EMBED_LEN_MAX) {
+ ns->flags |= MRB_STR_EMBED;
+ ns->flags &= ~MRB_STR_EMBED_LEN_MASK;
+ ns->flags |= (size_t)len << MRB_STR_EMBED_LEN_SHIFT;
+ 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';
+ }
+ }
+ return mrb_obj_value(ns);
+}
+
void
mrb_free_context(mrb_state *mrb, struct mrb_context *c)
{
@@ -131,55 +220,29 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c)
void
mrb_close(mrb_state *mrb)
{
- size_t i;
-
mrb_final_core(mrb);
/* free */
mrb_gc_free_gv(mrb);
- for (i=0; i<mrb->irep_len; i++) {
- mrb_irep_free(mrb, mrb->irep[i]);
- }
- mrb_free(mrb, mrb->irep);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
mrb_free_heap(mrb);
mrb_alloca_free(mrb);
+#ifndef MRB_GC_FIXED_ARENA
+ mrb_free(mrb, mrb->arena);
+#endif
mrb_free(mrb, mrb);
}
-#ifndef MRB_IREP_ARRAY_INIT_SIZE
-# define MRB_IREP_ARRAY_INIT_SIZE (256u)
-#endif
-
mrb_irep*
mrb_add_irep(mrb_state *mrb)
{
static const mrb_irep mrb_irep_zero = { 0 };
mrb_irep *irep;
- if (!mrb->irep) {
- size_t max = MRB_IREP_ARRAY_INIT_SIZE;
-
- if (mrb->irep_len > max) max = mrb->irep_len+1;
- mrb->irep = (mrb_irep **)mrb_calloc(mrb, max, sizeof(mrb_irep*));
- mrb->irep_capa = max;
- }
- else if (mrb->irep_capa <= mrb->irep_len) {
- size_t i;
- size_t old_capa = mrb->irep_capa;
- while (mrb->irep_capa <= mrb->irep_len) {
- mrb->irep_capa *= 2;
- }
- mrb->irep = (mrb_irep **)mrb_realloc(mrb, mrb->irep, sizeof(mrb_irep*)*mrb->irep_capa);
- for (i = old_capa; i < mrb->irep_capa; i++) {
- mrb->irep[i] = NULL;
- }
- }
irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
*irep = mrb_irep_zero;
- mrb->irep[mrb->irep_len] = irep;
- irep->idx = mrb->irep_len++;
+ irep->refcnt = 1;
return irep;
}
diff --git a/src/string.c b/src/string.c
index f3a788df3..ebc579ec5 100644
--- a/src/string.c
+++ b/src/string.c
@@ -5,12 +5,7 @@
*/
#include <ctype.h>
-#ifndef SIZE_MAX
- /* Some versions of VC++
- * has SIZE_MAX in stdint.h
- */
-# include <limits.h>
-#endif
+#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -21,24 +16,74 @@
#include "mruby/string.h"
#include "re.h"
+#define STR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
+#define STR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED)
+#define STR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
+#define STR_SET_EMBED_LEN(s, n) do {\
+ size_t tmp_n = (n);\
+ s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
+ s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
+} while (0)
+#define STR_SET_LEN(s, n) do {\
+ if (STR_EMBED_P(s)) {\
+ STR_SET_EMBED_LEN((s),(n));\
+ } else {\
+ s->as.heap.len = (mrb_int)(n);\
+ }\
+} while (0)
+#define RSTRING_EMBED_LEN(s) \
+ (size_t)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
+#define STR_EMBED_LEN(s)\
+ (size_t)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
+#define STR_PTR(s) ((STR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
+#define STR_LEN(s) ((STR_EMBED_P(s)) ? STR_EMBED_LEN(s) : (size_t)(s)->as.heap.len)
+
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
typedef struct mrb_shared_string {
- mrb_bool nofree;
+ mrb_bool nofree : 1;
int refcnt;
char *ptr;
mrb_int len;
} mrb_shared_string;
-#define MRB_STR_SHARED 1
-#define MRB_STR_NOFREE 2
+#define STR_SHARED_P(s) ((s)->flags & MRB_STR_SHARED)
+#define STR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
+#define STR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
+mrb_int
+mrb_str_strlen(mrb_state *mrb, struct RString *s)
+{
+ mrb_int i, max = STR_LEN(s);
+ char *p = STR_PTR(s);
+
+ if (!p) return 0;
+ for (i=0; i<max; i++) {
+ if (p[i] == '\0') {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ }
+ }
+ return max;
+}
+
#define RESIZE_CAPA(s,capacity) do {\
- s->ptr = (char *)mrb_realloc(mrb, s->ptr, (capacity)+1);\
- s->aux.capa = capacity;\
+ if (STR_EMBED_P(s)) {\
+ if (RSTRING_EMBED_LEN_MAX < (capacity)) {\
+ char *const __tmp__ = (char *)mrb_malloc(mrb, (capacity)+1);\
+ const mrb_int __len__ = STR_EMBED_LEN(s);\
+ memcpy(__tmp__, s->as.ary, __len__);\
+ STR_UNSET_EMBED_FLAG(s);\
+ s->as.heap.ptr = __tmp__;\
+ s->as.heap.len = __len__;\
+ s->as.heap.aux.capa = (capacity);\
+ }\
+ } else {\
+ s->as.heap.ptr = (char *)mrb_realloc(mrb, STR_PTR(s), (capacity)+1);\
+ s->as.heap.aux.capa = capacity;\
+ }\
} while(0)
static void
@@ -56,41 +101,43 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared)
void
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
- if (s->flags & MRB_STR_SHARED) {
- mrb_shared_string *shared = s->aux.shared;
+ if (STR_SHARED_P(s)) {
+ mrb_shared_string *shared = s->as.heap.aux.shared;
- if (shared->refcnt == 1 && s->ptr == shared->ptr) {
- s->ptr = shared->ptr;
- s->aux.capa = shared->len;
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.ptr = shared->ptr;
+ s->as.heap.aux.capa = shared->len;
+ STR_PTR(s)[s->as.heap.len] = '\0';
mrb_free(mrb, shared);
}
else {
char *ptr, *p;
mrb_int len;
- p = s->ptr;
- len = s->len;
+ p = STR_PTR(s);
+ len = s->as.heap.len;
ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
if (p) {
memcpy(ptr, p, len);
}
- ptr[len] = '\0';
- s->ptr = ptr;
- s->aux.capa = len;
+ ptr[len] = '\0';
+ s->as.heap.ptr = ptr;
+ s->as.heap.aux.capa = len;
str_decref(mrb, shared);
}
- s->flags &= ~MRB_STR_SHARED;
+ STR_UNSET_SHARED_FLAG(s);
return;
}
if (s->flags & MRB_STR_NOFREE) {
- char *p = s->ptr;
+ char *p = s->as.heap.ptr;
- s->ptr = (char *)mrb_malloc(mrb, (size_t)s->len+1);
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
if (p) {
- memcpy(s->ptr, p, s->len);
+ memcpy(STR_PTR(s), p, s->as.heap.len);
}
- s->ptr[s->len] = '\0';
- s->aux.capa = s->len;
+ STR_PTR(s)[s->as.heap.len] = '\0';
+ s->as.heap.aux.capa = s->as.heap.len;
+ s->flags &= ~MRB_STR_NOFREE;
return;
}
}
@@ -98,31 +145,21 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
mrb_value
mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
{
- int slen;
+ mrb_int slen;
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- slen = s->len;
+ slen = STR_LEN(s);
if (len != slen) {
if (slen < len || slen - len > 256) {
RESIZE_CAPA(s, len);
}
- s->len = len;
- s->ptr[len] = '\0'; /* sentinel */
+ STR_SET_LEN(s, len);
+ STR_PTR(s)[len] = '\0'; /* sentinel */
}
return str;
}
-static inline void
-str_mod_check(mrb_state *mrb, mrb_value str, char *p, mrb_int len)
-{
- struct RString *s = mrb_str_ptr(str);
-
- if (s->ptr != p || s->len != len) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "string modified");
- }
-}
-
#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
/* char offset to byte offset */
@@ -133,22 +170,33 @@ mrb_str_offset(mrb_state *mrb, mrb_value str, int pos)
}
static struct RString*
-str_new(mrb_state *mrb, const char *p, mrb_int len)
+str_new(mrb_state *mrb, const char *p, size_t len)
{
struct RString *s;
s = mrb_obj_alloc_string(mrb);
- s->len = len;
- s->aux.capa = len;
- s->ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
- if (p) {
- memcpy(s->ptr, p, len);
+ if (len < RSTRING_EMBED_LEN_MAX) {
+ STR_SET_EMBED_FLAG(s);
+ STR_SET_EMBED_LEN(s,len);
+ if (p) {
+ memcpy(s->as.ary, p, len);
+ }
+ } else {
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = len;
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1);
+ if (p) {
+ memcpy(s->as.heap.ptr, p, len);
+ }
}
- s->ptr[len] = '\0';
+ STR_PTR(s)[len] = '\0';
return s;
}
-void
+static void
str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj)
{
s->c = mrb_str_ptr(obj)->c;
@@ -168,19 +216,22 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str)
#endif
mrb_value
-mrb_str_buf_new(mrb_state *mrb, mrb_int capa)
+mrb_str_buf_new(mrb_state *mrb, size_t capa)
{
struct RString *s;
s = mrb_obj_alloc_string(mrb);
+ if (capa >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big");
+ }
if (capa < MRB_STR_BUF_MIN_SIZE) {
capa = MRB_STR_BUF_MIN_SIZE;
}
- s->len = 0;
- s->aux.capa = capa;
- s->ptr = (char *)mrb_malloc(mrb, capa+1);
- s->ptr[0] = '\0';
+ s->as.heap.len = 0;
+ s->as.heap.aux.capa = capa;
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1);
+ STR_PTR(s)[0] = '\0';
return mrb_obj_value(s);
}
@@ -188,20 +239,25 @@ mrb_str_buf_new(mrb_state *mrb, mrb_int capa)
static void
str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
{
- mrb_int capa;
- mrb_int total;
+ size_t capa;
+ size_t total;
ptrdiff_t off = -1;
+ if (len == 0) return;
mrb_str_modify(mrb, s);
- if (ptr >= s->ptr && ptr <= s->ptr + s->len) {
- off = ptr - s->ptr;
+ if (ptr >= STR_PTR(s) && ptr <= STR_PTR(s) + (size_t)STR_LEN(s)) {
+ off = ptr - STR_PTR(s);
}
- if (len == 0) return;
- capa = s->aux.capa;
- if (s->len >= MRB_INT_MAX - (mrb_int)len) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string sizes too big");
+
+ if (STR_EMBED_P(s))
+ capa = RSTRING_EMBED_LEN_MAX;
+ else
+ capa = s->as.heap.aux.capa;
+
+ if (STR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
- total = s->len+len;
+ total = STR_LEN(s)+len;
if (capa <= total) {
while (total > capa) {
if (capa + 1 >= MRB_INT_MAX / 2) {
@@ -213,11 +269,12 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
RESIZE_CAPA(s, capa);
}
if (off != -1) {
- ptr = s->ptr + off;
+ ptr = STR_PTR(s) + off;
}
- memcpy(s->ptr + s->len, ptr, len);
- s->len = total;
- s->ptr[total] = '\0'; /* sentinel */
+ memcpy(STR_PTR(s) + STR_LEN(s), ptr, len);
+ mrb_assert(total <= MRB_INT_MAX);
+ STR_SET_LEN(s, total);
+ STR_PTR(s)[total] = '\0'; /* sentinel */
}
mrb_value
@@ -252,9 +309,6 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p)
if (p) {
len = strlen(p);
- if ((mrb_int)len < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "argument too big");
- }
}
else {
len = 0;
@@ -270,10 +324,13 @@ mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
{
struct RString *s;
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+ }
s = mrb_obj_alloc_string(mrb);
- s->len = len;
- s->aux.capa = 0; /* nofree */
- s->ptr = (char *)p;
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = 0; /* nofree */
+ s->as.heap.ptr = (char *)p;
s->flags = MRB_STR_NOFREE;
return mrb_obj_value(s);
}
@@ -281,10 +338,12 @@ mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
void
mrb_gc_free_str(mrb_state *mrb, struct RString *str)
{
- if (str->flags & MRB_STR_SHARED)
- str_decref(mrb, str->aux.shared);
+ if (STR_EMBED_P(str))
+ /* no code */;
+ else if (STR_SHARED_P(str))
+ str_decref(mrb, str->as.heap.aux.shared);
else if ((str->flags & MRB_STR_NOFREE) == 0)
- mrb_free(mrb, str->ptr);
+ mrb_free(mrb, str->as.heap.ptr);
}
char *
@@ -297,68 +356,51 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
}
s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
- if ((strlen(s->ptr) ^ s->len) != 0) {
+ if ((strlen(STR_PTR(s)) ^ STR_LEN(s)) != 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
- return s->ptr;
+ return STR_PTR(s);
}
static void
str_make_shared(mrb_state *mrb, struct RString *s)
{
- if (!(s->flags & MRB_STR_SHARED)) {
+ if (!STR_SHARED_P(s)) {
mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
shared->refcnt = 1;
- if (s->flags & MRB_STR_NOFREE) {
+ if (STR_EMBED_P(s)) {
+ const mrb_int len = STR_EMBED_LEN(s);
+ char *const tmp = (char *)mrb_malloc(mrb, len+1);
+ memcpy(tmp, s->as.ary, len);
+ tmp[len] = '\0';
+ STR_UNSET_EMBED_FLAG(s);
+ s->as.heap.ptr = tmp;
+ s->as.heap.len = len;
+ shared->nofree = FALSE;
+ shared->ptr = s->as.heap.ptr;
+ }
+ else if (s->flags & MRB_STR_NOFREE) {
shared->nofree = TRUE;
- shared->ptr = s->ptr;
+ shared->ptr = s->as.heap.ptr;
s->flags &= ~MRB_STR_NOFREE;
}
else {
shared->nofree = FALSE;
- if (s->aux.capa > s->len) {
- s->ptr = shared->ptr = (char *)mrb_realloc(mrb, s->ptr, s->len+1);
+ if (s->as.heap.aux.capa > s->as.heap.len) {
+ s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, s->as.heap.ptr, s->as.heap.len+1);
}
else {
- shared->ptr = s->ptr;
+ shared->ptr = s->as.heap.ptr;
}
}
- shared->len = s->len;
- s->aux.shared = shared;
- s->flags |= MRB_STR_SHARED;
+ shared->len = s->as.heap.len;
+ s->as.heap.aux.shared = shared;
+ STR_SET_SHARED_FLAG(s);
}
}
/*
- * call-seq: (Caution! string literal)
- * String.new(str="") => new_str
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
-
-mrb_value
-mrb_str_literal(mrb_state *mrb, mrb_value str)
-{
- struct RString *s, *orig;
- mrb_shared_string *shared;
-
- s = mrb_obj_alloc_string(mrb);
- orig = mrb_str_ptr(str);
- if (!(orig->flags & MRB_STR_SHARED)) {
- str_make_shared(mrb, orig);
- }
- shared = orig->aux.shared;
- shared->refcnt++;
- s->ptr = shared->ptr;
- s->len = shared->len;
- s->aux.shared = shared;
- s->flags |= MRB_STR_SHARED;
-
- return mrb_obj_value(s);
-}
-
-/*
* call-seq:
* char* str = String("abcd"), len=strlen("abcd")
*
@@ -369,8 +411,8 @@ mrb_str_body(mrb_value str, int *len_p)
{
struct RString *s = mrb_str_ptr(str);
- *len_p = s->len;
- return s->ptr;
+ *len_p = STR_LEN(s);
+ return STR_PTR(s);
}
/*
@@ -390,15 +432,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
- len = s1->len + s2->len;
+ len = STR_LEN(s1) + STR_LEN(s2);
- if (s1->aux.capa < len) {
- s1->aux.capa = len;
- s1->ptr = (char *)mrb_realloc(mrb, s1->ptr, len+1);
+ if (RSTRING_CAPA(self) < len) {
+ RESIZE_CAPA(s1, len);
}
- memcpy(s1->ptr+s1->len, s2->ptr, s2->len);
- s1->len = len;
- s1->ptr[len] = '\0';
+ memcpy(STR_PTR(s1)+STR_LEN(s1), STR_PTR(s2), STR_LEN(s2));
+ STR_SET_LEN(s1, len);
+ STR_PTR(s1)[len] = '\0';
}
/*
@@ -414,9 +455,9 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
struct RString *s2 = mrb_str_ptr(b);
struct RString *t;
- t = str_new(mrb, 0, s->len + s2->len);
- memcpy(t->ptr, s->ptr, s->len);
- memcpy(t->ptr + s->len, s2->ptr, s2->len);
+ t = str_new(mrb, 0, STR_LEN(s) + STR_LEN(s2));
+ memcpy(STR_PTR(t), STR_PTR(s), STR_LEN(s));
+ memcpy(STR_PTR(t) + STR_LEN(s), STR_PTR(s2), STR_LEN(s2));
return mrb_obj_value(t);
}
@@ -448,7 +489,7 @@ static mrb_value
mrb_str_bytesize(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(s->len);
+ return mrb_fixnum_value(STR_LEN(s));
}
/* 15.2.10.5.26 */
@@ -463,7 +504,7 @@ mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(s->len);
+ return mrb_fixnum_value(STR_LEN(s));
}
/* 15.2.10.5.1 */
@@ -494,7 +535,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);
- p = str2->ptr;
+ p = STR_PTR(str2);
if (len > 0) {
n = RSTRING_LEN(self);
memcpy(p, RSTRING_PTR(self), n);
@@ -504,7 +545,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
}
memcpy(p + n, p, len-n);
}
- p[str2->len] = '\0';
+ p[STR_LEN(str2)] = '\0';
return mrb_obj_value(str2);
}
@@ -528,11 +569,11 @@ mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
struct RString *s1 = mrb_str_ptr(str1);
struct RString *s2 = mrb_str_ptr(str2);
- len = lesser(s1->len, s2->len);
- retval = memcmp(s1->ptr, s2->ptr, len);
+ len = lesser(STR_LEN(s1), STR_LEN(s2));
+ retval = memcmp(STR_PTR(s1), STR_PTR(s2), len);
if (retval == 0) {
- if (s1->len == s2->len) return 0;
- if (s1->len > s2->len) return 1;
+ if (STR_LEN(s1) == STR_LEN(s2)) return 0;
+ if (STR_LEN(s1) > STR_LEN(s2)) return 1;
return -1;
}
if (retval > 0) return 1;
@@ -573,10 +614,10 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
mrb_get_args(mrb, "o", &str2);
if (!mrb_string_p(str2)) {
- if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "to_s", 4))) {
+ if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_s"))) {
return mrb_nil_value();
}
- else if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "<=>", 3))) {
+ else if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "<=>"))) {
return mrb_nil_value();
}
else {
@@ -609,10 +650,10 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2)
mrb_bool
mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2)
{
- if (mrb_obj_equal(mrb, str1, str2)) return TRUE;
+ if (mrb_immediate_p(str2)) return FALSE;
if (!mrb_string_p(str2)) {
if (mrb_nil_p(str2)) return FALSE;
- if (!mrb_respond_to(mrb, str2, mrb_intern2(mrb, "to_str", 6))) {
+ if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) {
return FALSE;
}
str2 = mrb_funcall(mrb, str2, "to_str", 0);
@@ -713,7 +754,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
else if (m < 1) {
return 0;
}
- else if (m == 1) {
+ else if (m == 1) {
const unsigned char *ys = y, *ye = ys + n;
for (; y < ye; ++y) {
if (*x == *y)
@@ -755,10 +796,11 @@ mrb_str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
mrb_value
mrb_str_dup(mrb_state *mrb, mrb_value str)
{
- /* should return shared string */
struct RString *s = mrb_str_ptr(str);
+ struct RString *dup = str_new(mrb, 0, 0);
- return mrb_str_new(mrb, s->ptr, s->len);
+ str_with_class(mrb, dup, str);
+ return str_replace(mrb, dup, s);
}
static mrb_value
@@ -785,12 +827,10 @@ num_index:
/* check if indx is Range */
{
mrb_int beg, len;
- mrb_value tmp;
len = RSTRING_LEN(str);
if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
- tmp = mrb_str_subseq(mrb, str, beg, len);
- return tmp;
+ return mrb_str_subseq(mrb, str, beg, len);
}
else {
return mrb_nil_value();
@@ -889,8 +929,8 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (s->len == 0 || !s->ptr) return mrb_nil_value();
- p = s->ptr; pend = s->ptr + s->len;
+ if (STR_LEN(s) == 0 || !STR_PTR(s)) return mrb_nil_value();
+ p = STR_PTR(s); pend = STR_PTR(s) + STR_LEN(s);
if (ISLOWER(*p)) {
*p = TOUPPER(*p);
modify = 1;
@@ -946,29 +986,29 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- len = s->len;
+ len = STR_LEN(s);
if (mrb_get_args(mrb, "|S", &rs) == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
- if (s->ptr[len-1] == '\n') {
- s->len--;
- if (s->len > 0 &&
- s->ptr[s->len-1] == '\r') {
- s->len--;
+ if (STR_PTR(s)[len-1] == '\n') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
+ if (STR_LEN(s) > 0 &&
+ STR_PTR(s)[STR_LEN(s)-1] == '\r') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
}
}
- else if (s->ptr[len-1] == '\r') {
- s->len--;
+ else if (STR_PTR(s)[len-1] == '\r') {
+ STR_SET_LEN(s, STR_LEN(s) - 1);
}
else {
return mrb_nil_value();
}
- s->ptr[s->len] = '\0';
+ STR_PTR(s)[STR_LEN(s)] = '\0';
return str;
}
if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value();
- p = s->ptr;
+ p = STR_PTR(s);
rslen = RSTRING_LEN(rs);
if (rslen == 0) {
while (len>0 && p[len-1] == '\n') {
@@ -976,8 +1016,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (len>0 && p[len-1] == '\r')
len--;
}
- if (len < s->len) {
- s->len = len;
+ if (len < STR_LEN(s)) {
+ STR_SET_LEN(s, len);
p[len] = '\0';
return str;
}
@@ -994,8 +1034,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (p[len-1] == newline &&
(rslen <= 1 ||
memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) {
- s->len = len - rslen;
- p[s->len] = '\0';
+ STR_SET_LEN(s, len - rslen);
+ p[STR_LEN(s)] = '\0';
return str;
}
return mrb_nil_value();
@@ -1045,17 +1085,17 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (s->len > 0) {
- int len;
- len = s->len - 1;
- if (s->ptr[len] == '\n') {
+ if (STR_LEN(s) > 0) {
+ mrb_int len;
+ len = STR_LEN(s) - 1;
+ if (STR_PTR(s)[len] == '\n') {
if (len > 0 &&
- s->ptr[len-1] == '\r') {
+ STR_PTR(s)[len-1] == '\r') {
len--;
}
}
- s->len = len;
- s->ptr[len] = '\0';
+ STR_SET_LEN(s, len);
+ STR_PTR(s)[len] = '\0';
return str;
}
return mrb_nil_value();
@@ -1103,8 +1143,8 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- p = s->ptr;
- pend = s->ptr + s->len;
+ p = STR_PTR(s);
+ pend = STR_PTR(s) + STR_LEN(s);
while (p < pend) {
if (ISUPPER(*p)) {
*p = TOLOWER(*p);
@@ -1153,7 +1193,7 @@ mrb_str_empty_p(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_bool_value(s->len == 0);
+ return mrb_bool_value(STR_LEN(s) == 0);
}
/* 15.2.10.5.17 */
@@ -1182,14 +1222,18 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
mrb_shared_string *shared;
orig = mrb_str_ptr(str);
- str_make_shared(mrb, orig);
- shared = orig->aux.shared;
- s = mrb_obj_alloc_string(mrb);
- s->ptr = orig->ptr + beg;
- s->len = len;
- s->aux.shared = shared;
- s->flags |= MRB_STR_SHARED;
- shared->refcnt++;
+ if (STR_EMBED_P(orig)) {
+ s = str_new(mrb, orig->as.ary+beg, len);
+ } else {
+ str_make_shared(mrb, orig);
+ shared = orig->as.heap.aux.shared;
+ s = mrb_obj_alloc_string(mrb);
+ s->as.heap.ptr = orig->as.heap.ptr + beg;
+ s->as.heap.len = len;
+ s->as.heap.aux.shared = shared;
+ STR_SET_SHARED_FLAG(s);
+ shared->refcnt++;
+ }
return mrb_obj_value(s);
}
@@ -1230,8 +1274,8 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
{
/* 1-8-7 */
struct RString *s = mrb_str_ptr(str);
- mrb_int len = s->len;
- char *p = s->ptr;
+ mrb_int len = STR_LEN(s);
+ char *p = STR_PTR(s);
mrb_int key = 0;
while (len--) {
@@ -1277,7 +1321,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
mrb_bool include_p;
mrb_get_args(mrb, "o", &str2);
- if (mrb_type(str2) == MRB_TT_FIXNUM) {
+ if (mrb_fixnum_p(str2)) {
include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL);
}
else {
@@ -1377,38 +1421,36 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
static mrb_value
str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
- if (s2->flags & MRB_STR_SHARED) {
+ long len;
+
+ len = STR_LEN(s2);
+ if (STR_SHARED_P(s2)) {
L_SHARE:
- if (s1->flags & MRB_STR_SHARED){
- str_decref(mrb, s1->aux.shared);
+ if (STR_SHARED_P(s1)) {
+ str_decref(mrb, s1->as.heap.aux.shared);
}
- else {
- mrb_free(mrb, s1->ptr);
+ else if (!STR_EMBED_P(s1) && !(s1->flags & MRB_STR_NOFREE)) {
+ mrb_free(mrb, s1->as.heap.ptr);
}
- s1->ptr = s2->ptr;
- s1->len = s2->len;
- s1->aux.shared = s2->aux.shared;
- s1->flags |= MRB_STR_SHARED;
- s1->aux.shared->refcnt++;
- }
- else if (s2->len > STR_REPLACE_SHARED_MIN) {
- str_make_shared(mrb, s2);
- goto L_SHARE;
+ STR_UNSET_EMBED_FLAG(s1);
+ s1->as.heap.ptr = s2->as.heap.ptr;
+ s1->as.heap.len = len;
+ s1->as.heap.aux.shared = s2->as.heap.aux.shared;
+ STR_SET_SHARED_FLAG(s1);
+ s1->as.heap.aux.shared->refcnt++;
}
else {
- if (s1->flags & MRB_STR_SHARED) {
- str_decref(mrb, s1->aux.shared);
- s1->flags &= ~MRB_STR_SHARED;
- s1->ptr = (char *)mrb_malloc(mrb, s2->len+1);
+ if (len <= RSTRING_EMBED_LEN_MAX) {
+ STR_SET_EMBED_FLAG(s1);
+ memcpy(s1->as.ary, STR_PTR(s2), len);
+ STR_SET_EMBED_LEN(s1, len);
}
else {
- s1->ptr = (char *)mrb_realloc(mrb, s1->ptr, s2->len+1);
+ str_make_shared(mrb, s2);
+ goto L_SHARE;
}
- memcpy(s1->ptr, s2->ptr, s2->len);
- s1->ptr[s2->len] = 0;
- s1->len = s2->len;
- s1->aux.capa = s2->len;
}
+
return mrb_obj_value(s1);
}
@@ -1499,10 +1541,10 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
struct RString *p_str;
char *p1;
char *p2;
- intptr_t n = (intptr_t)p;
+ uintptr_t n = (uintptr_t)p;
p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4);
- p1 = p_str->ptr;
+ p1 = STR_PTR(p_str);
*p1++ = '0';
*p1++ = 'x';
p2 = p1;
@@ -1512,7 +1554,7 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
n /= 16;
} while (n > 0);
*p2 = '\0';
- p_str->len = (mrb_int)(p2 - p_str->ptr);
+ STR_SET_LEN(p_str, (mrb_int)(p2 - STR_PTR(p_str)));
while (p1 < p2) {
const char c = *p1;
@@ -1524,6 +1566,12 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
}
mrb_value
+mrb_string_type(mrb_state *mrb, mrb_value str)
+{
+ return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str");
+}
+
+mrb_value
mrb_check_string_type(mrb_state *mrb, mrb_value str)
{
return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str");
@@ -1545,12 +1593,12 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
struct RString *s2;
char *s, *e, *p;
- if (RSTRING(str)->len <= 1) return mrb_str_dup(mrb, str);
+ if (RSTRING_LEN(str) <= 1) return mrb_str_dup(mrb, str);
- s2 = str_new(mrb, 0, RSTRING(str)->len);
+ s2 = str_new(mrb, 0, RSTRING_LEN(str));
str_with_class(mrb, s2, str);
s = RSTRING_PTR(str); e = RSTRING_END(str) - 1;
- p = s2->ptr;
+ p = STR_PTR(s2);
while (e >= s) {
*p++ = *e--;
@@ -1573,9 +1621,9 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
char c;
mrb_str_modify(mrb, s);
- if (s->len > 1) {
- p = s->ptr;
- e = p + s->len - 1;
+ if (STR_LEN(s) > 1) {
+ p = STR_PTR(s);
+ e = p + STR_LEN(s) - 1;
while (p < e) {
c = *p;
*p++ = *e;
@@ -1608,21 +1656,20 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
{
char *s, *sbeg, *t;
struct RString *ps = mrb_str_ptr(str);
- struct RString *psub = mrb_str_ptr(sub);
- mrb_int len = psub->len;
+ mrb_int len = RSTRING_LEN(sub);
/* substring longer than string */
- if (ps->len < len) return -1;
- if (ps->len - pos < len) {
- pos = ps->len - len;
+ if (STR_LEN(ps) < len) return -1;
+ if (STR_LEN(ps) - pos < len) {
+ pos = STR_LEN(ps) - len;
}
- sbeg = ps->ptr;
- s = ps->ptr + pos;
- t = psub->ptr;
+ sbeg = STR_PTR(ps);
+ s = STR_PTR(ps) + pos;
+ t = RSTRING_PTR(sub);
if (len) {
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
- return s - ps->ptr;
+ return s - STR_PTR(ps);
}
s--;
}
@@ -1659,7 +1706,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
int argc;
mrb_value sub;
mrb_value vpos;
- int pos, len = RSTRING_LEN(str);
+ mrb_int pos, len = RSTRING_LEN(str);
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 2) {
@@ -1690,7 +1737,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
mrb_int len = RSTRING_LEN(str);
unsigned char *p = (unsigned char*)RSTRING_PTR(str);
- for (pos=len;pos>=0;pos--) {
+ for (pos=len-1;pos>=0;pos--) {
if (p[pos] == c) return mrb_fixnum_value(pos);
}
return mrb_nil_value();
@@ -1716,22 +1763,22 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
}
static const char isspacetable[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
@@ -1853,7 +1900,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
else if (split_type == string) {
- char *ptr = RSTRING_PTR(str);
+ char *ptr = RSTRING_PTR(str); // s->as.ary
char *temp = ptr;
char *eptr = RSTRING_END(str);
mrb_int slen = RSTRING_LEN(spat);
@@ -1906,10 +1953,10 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
mrb_value
mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
{
- char *end;
+ const char *p;
char sign = 1;
- int c;
- unsigned long n;
+ int c, uscore;
+ unsigned long n = 0;
mrb_int val;
#undef ISDIGIT
@@ -1996,14 +2043,14 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break;
} /* end of switch (base) { */
if (*str == '0') { /* squeeze preceeding 0s */
- int us = 0;
+ uscore = 0;
while ((c = *++str) == '0' || c == '_') {
if (c == '_') {
- if (++us >= 2)
+ if (++uscore >= 2)
break;
}
else
- us = 0;
+ uscore = 0;
}
if (!(c = *str) || ISSPACE(c)) --str;
}
@@ -2014,15 +2061,33 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
return mrb_fixnum_value(0);
}
- n = strtoul((char*)str, &end, base);
+ uscore = 0;
+ for (p=str;*p;p++) {
+ if (*p == '_') {
+ if (uscore == 0) {
+ uscore++;
+ continue;
+ }
+ if (badcheck) goto bad;
+ break;
+ }
+ uscore = 0;
+ c = conv_digit(*p);
+ if (c < 0 || c >= base) {
+ if (badcheck) goto bad;
+ break;
+ }
+ n *= base;
+ n += c;
+ }
if (n > MRB_INT_MAX) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str));
}
val = n;
if (badcheck) {
- if (end == str) goto bad; /* no number */
- while (*end && ISSPACE(*end)) end++;
- if (*end) goto bad; /* trailing garbage */
+ if (p == str) goto bad; /* no number */
+ while (*p && ISSPACE(*p)) p++;
+ if (*p) goto bad; /* trailing garbage */
}
return mrb_fixnum_value(sign ? val : -val);
@@ -2036,19 +2101,21 @@ char *
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
struct RString *ps = mrb_str_ptr(*ptr);
- char *s = ps->ptr;
+ mrb_int len = mrb_str_strlen(mrb, ps);
+ char *p = STR_PTR(ps);
- if (!s || ps->len != strlen(s)) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ if (!p || p[len] != '\0') {
+ mrb_str_modify(mrb, ps);
+ return STR_PTR(ps);
}
- return s;
+ return p;
}
mrb_value
-mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, int badcheck)
+mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, mrb_bool badcheck)
{
char *s;
- int len;
+ mrb_int len;
str = mrb_str_to_str(mrb, str);
if (badcheck) {
@@ -2061,7 +2128,7 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, int badcheck)
len = RSTRING_LEN(str);
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = temp_str->ptr;
+ s = STR_PTR(temp_str);
}
}
return mrb_cstr_to_inum(mrb, s, base, badcheck);
@@ -2104,11 +2171,11 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
if (base < 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base));
}
- return mrb_str_to_inum(mrb, self, base, 0/*Qfalse*/);
+ return mrb_str_to_inum(mrb, self, base, FALSE);
}
double
-mrb_cstr_to_dbl(mrb_state *mrb, const char * p, int badcheck)
+mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
{
char *end;
double d;
@@ -2177,10 +2244,10 @@ bad:
}
double
-mrb_str_to_dbl(mrb_state *mrb, mrb_value str, int badcheck)
+mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
{
char *s;
- int len;
+ mrb_int len;
str = mrb_str_to_str(mrb, str);
s = RSTRING_PTR(str);
@@ -2191,7 +2258,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, int badcheck)
}
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = temp_str->ptr;
+ s = STR_PTR(temp_str);
}
}
return mrb_cstr_to_dbl(mrb, s, badcheck);
@@ -2214,7 +2281,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, int badcheck)
static mrb_value
mrb_str_to_f(mrb_state *mrb, mrb_value self)
{
- return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, 0/*Qfalse*/));
+ return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, FALSE));
}
/* 15.2.10.5.40 */
@@ -2330,8 +2397,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
result = str_new(mrb, 0, len);
str_with_class(mrb, result, str);
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
- q = result->ptr;
-
+ q = STR_PTR(result);
*q++ = '"';
while (p < pend) {
unsigned char c = *p++;
@@ -2347,47 +2413,47 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
*q++ = '\\';
*q++ = 'n';
break;
-
+
case '\r':
*q++ = '\\';
*q++ = 'r';
break;
-
+
case '\t':
*q++ = '\\';
*q++ = 't';
break;
-
+
case '\f':
*q++ = '\\';
*q++ = 'f';
break;
-
+
case '\013':
*q++ = '\\';
*q++ = 'v';
break;
-
+
case '\010':
*q++ = '\\';
*q++ = 'b';
break;
-
+
case '\007':
*q++ = '\\';
*q++ = 'a';
break;
-
+
case '\033':
*q++ = '\\';
*q++ = 'e';
break;
-
+
case '#':
if (IS_EVSTR(p, pend)) *q++ = '\\';
*q++ = '#';
break;
-
+
default:
if (ISPRINT(c)) {
*q++ = c;
@@ -2401,16 +2467,13 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
}
}
}
- *q++ = '"';
+ *q = '"';
return mrb_obj_value(result);
}
mrb_value
mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
{
- if ((mrb_int)len < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
- }
str_buf_cat(mrb, mrb_str_ptr(str), ptr, len);
return str;
}
@@ -2446,11 +2509,11 @@ 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(mrb, "\"", 1);
+ mrb_value result = mrb_str_new_lit(mrb, "\"");
p = RSTRING_PTR(str); pend = RSTRING_END(str);
for (;p < pend; p++) {
- unsigned int c, cc;
+ unsigned char c, cc;
c = *p;
if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) {
@@ -2489,7 +2552,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
continue;
}
}
- mrb_str_buf_cat(mrb, result, "\"", 1);
+ mrb_str_cat_lit(mrb, result, "\"");
return result;
}
@@ -2507,8 +2570,8 @@ static mrb_value
mrb_str_bytes(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
- mrb_value a = mrb_ary_new_capa(mrb, s->len);
- unsigned char *p = (unsigned char *)(s->ptr), *pend = p + s->len;
+ mrb_value a = mrb_ary_new_capa(mrb, STR_LEN(s));
+ unsigned char *p = (unsigned char *)(STR_PTR(s)), *pend = p + STR_LEN(s);
while (p < pend) {
mrb_ary_push(mrb, a, mrb_fixnum_value(p[0]));
@@ -2525,15 +2588,13 @@ mrb_init_string(mrb_state *mrb)
s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
- mrb_include_module(mrb, s, mrb_class_get(mrb, "Comparable"));
- mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */
mrb_define_method(mrb, s, "bytesize", mrb_str_bytesize, MRB_ARGS_NONE());
- mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */
- mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.26 */
- mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */
- mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.3 */
- mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */
+
+ mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */
+ mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */
+ 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, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */
mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.8 */
@@ -2552,17 +2613,19 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */
mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */
mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */
+ mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.26 */
mrb_define_method(mrb, s, "replace", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.28 */
mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); /* 15.2.10.5.29 */
mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); /* 15.2.10.5.30 */
mrb_define_method(mrb, s, "rindex", mrb_str_rindex_m, MRB_ARGS_ANY()); /* 15.2.10.5.31 */
+ mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */
mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.34 */
mrb_define_method(mrb, s, "split", mrb_str_split_m, MRB_ARGS_ANY()); /* 15.2.10.5.35 */
- mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.38 */
- mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.39 */
+ mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.38 */
+ mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */
mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */
- mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */
+ mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */
mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_REQ(1)); /* 15.2.10.5.42 */
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.43 */
diff --git a/src/symbol.c b/src/symbol.c
index c145a4a1a..fd0b116bd 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -5,7 +5,6 @@
*/
#include <ctype.h>
-#include <limits.h>
#include <string.h>
#include "mruby.h"
#include "mruby/khash.h"
@@ -13,7 +12,8 @@
/* ------------------------------------------------------ */
typedef struct symbol_name {
- size_t len;
+ mrb_bool lit : 1;
+ uint16_t len;
const char *name;
} symbol_name;
@@ -31,11 +31,11 @@ sym_hash_func(mrb_state *mrb, const symbol_name s)
}
#define sym_hash_equal(mrb,a, b) (a.len == b.len && memcmp(a.name, b.name, a.len) == 0)
-KHASH_DECLARE(n2s, symbol_name, mrb_sym, 1)
-KHASH_DEFINE (n2s, symbol_name, mrb_sym, 1, sym_hash_func, sym_hash_equal)
+KHASH_DECLARE(n2s, symbol_name, mrb_sym, TRUE)
+KHASH_DEFINE (n2s, symbol_name, mrb_sym, TRUE, sym_hash_func, sym_hash_equal)
/* ------------------------------------------------------ */
-mrb_sym
-mrb_intern2(mrb_state *mrb, const char *name, size_t len)
+static mrb_sym
+sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
{
khash_t(n2s) *h = mrb->name2sym;
symbol_name sname;
@@ -43,46 +43,70 @@ mrb_intern2(mrb_state *mrb, const char *name, size_t len)
mrb_sym sym;
char *p;
+ if (len > UINT16_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
+ sname.lit = lit;
sname.len = len;
sname.name = name;
- k = kh_get(n2s, h, sname);
+ k = kh_get(n2s, mrb, h, sname);
if (k != kh_end(h))
return kh_value(h, k);
sym = ++mrb->symidx;
- p = (char *)mrb_malloc(mrb, len+1);
- memcpy(p, name, len);
- p[len] = 0;
- sname.name = (const char*)p;
- k = kh_put(n2s, h, sname);
+ if (lit) {
+ sname.name = name;
+ }
+ else {
+ p = (char *)mrb_malloc(mrb, len+1);
+ memcpy(p, name, len);
+ p[len] = 0;
+ sname.name = (const char*)p;
+ }
+ k = kh_put(n2s, mrb, h, sname);
kh_value(h, k) = sym;
return sym;
}
mrb_sym
+mrb_intern(mrb_state *mrb, const char *name, size_t len)
+{
+ return sym_intern(mrb, name, len, FALSE);
+}
+
+mrb_sym
+mrb_intern_static(mrb_state *mrb, const char *name, size_t len)
+{
+ return sym_intern(mrb, name, len, TRUE);
+}
+
+mrb_sym
mrb_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_intern2(mrb, name, strlen(name));
+ return mrb_intern(mrb, name, strlen(name));
}
mrb_sym
mrb_intern_str(mrb_state *mrb, mrb_value str)
{
- return mrb_intern2(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
+ return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
mrb_value
mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
{
khash_t(n2s) *h = mrb->name2sym;
- symbol_name sname;
+ symbol_name sname = { 0 };
khiter_t k;
+ if (len > UINT16_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
sname.len = len;
sname.name = name;
- k = kh_get(n2s, h, sname);
+ k = kh_get(n2s, mrb, h, sname);
if (k != kh_end(h)) {
return mrb_symbol_value(kh_value(h, k));
}
@@ -92,7 +116,7 @@ mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
mrb_value
mrb_check_intern_cstr(mrb_state *mrb, const char *name)
{
- return mrb_check_intern(mrb, name, strlen(name));
+ return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
}
mrb_value
@@ -103,7 +127,7 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str)
/* lenp must be a pointer to a size_t variable */
const char*
-mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, size_t *lenp)
+mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
{
khash_t(n2s) *h = mrb->name2sym;
khiter_t k;
@@ -113,12 +137,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, size_t *lenp)
if (kh_exist(h, k)) {
if (kh_value(h, k) == sym) {
sname = kh_key(h, k);
- *lenp = sname.len;
+ if (lenp) *lenp = sname.len;
return sname.name;
}
}
}
- *lenp = 0;
+ if (lenp) *lenp = 0;
return NULL; /* missing */
}
@@ -129,8 +153,14 @@ mrb_free_symtbl(mrb_state *mrb)
khiter_t k;
for (k = kh_begin(h); k != kh_end(h); k++)
- if (kh_exist(h, k)) mrb_free(mrb, (char*)kh_key(h, k).name);
- kh_destroy(n2s,mrb->name2sym);
+ if (kh_exist(h, k)) {
+ symbol_name s = kh_key(h, k);
+
+ if (!s.lit) {
+ mrb_free(mrb, (char*)s.name);
+ }
+ }
+ kh_destroy(n2s, mrb, mrb->name2sym);
}
void
@@ -210,7 +240,7 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
{
mrb_sym id = mrb_symbol(sym);
const char *p;
- size_t len;
+ mrb_int len;
p = mrb_sym2name_len(mrb, id, &len);
return mrb_str_new_static(mrb, p, len);
@@ -278,7 +308,7 @@ static mrb_bool
symname_p(const char *name)
{
const char *m = name;
- int localid = FALSE;
+ mrb_bool localid = FALSE;
if (!m) return FALSE;
switch (*m) {
@@ -362,16 +392,20 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
{
mrb_value str;
const char *name;
- size_t len;
+ mrb_int len;
mrb_sym id = mrb_symbol(sym);
+ char *sp;
name = mrb_sym2name_len(mrb, id, &len);
str = mrb_str_new(mrb, 0, len+1);
- RSTRING(str)->ptr[0] = ':';
- memcpy(RSTRING(str)->ptr+1, name, len);
+ sp = RSTRING_PTR(str);
+ RSTRING_PTR(str)[0] = ':';
+ memcpy(sp+1, name, len);
if (!symname_p(name) || strlen(name) != len) {
str = mrb_str_dump(mrb, str);
- memcpy(RSTRING(str)->ptr, ":\"", 2);
+ sp = RSTRING_PTR(str);
+ sp[0] = ':';
+ sp[1] = '"';
}
return str;
}
@@ -379,31 +413,26 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
mrb_value
mrb_sym2str(mrb_state *mrb, mrb_sym sym)
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(mrb, sym, &len);
- mrb_value str;
if (!name) return mrb_undef_value(); /* can't happen */
- str = mrb_str_new_static(mrb, name, len);
- if (symname_p(name) && strlen(name) == len) {
- return str;
- }
- return mrb_str_dump(mrb, str);
+ return mrb_str_new_static(mrb, name, len);
}
const char*
mrb_sym2name(mrb_state *mrb, mrb_sym sym)
{
- size_t len;
+ mrb_int len;
const char *name = mrb_sym2name_len(mrb, sym, &len);
if (!name) return NULL;
- if (symname_p(name) && strlen(name) == len) {
+ if (symname_p(name) && strlen(name) == (size_t)len) {
return name;
}
else {
mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
- return RSTRING(str)->ptr;
+ return RSTRING_PTR(str);
}
}
@@ -423,7 +452,7 @@ sym_cmp(mrb_state *mrb, mrb_value s1)
else {
const char *p1, *p2;
int retval;
- size_t len, len1, len2;
+ mrb_int len, len1, len2;
p1 = mrb_sym2name_len(mrb, sym1, &len1);
p2 = mrb_sym2name_len(mrb, sym2, &len2);
@@ -452,5 +481,4 @@ mrb_init_symbol(mrb_state *mrb)
mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1));
- mrb->init_sym = mrb_intern2(mrb, "initialize", 10);
}
diff --git a/src/variable.c b/src/variable.c
index 048b63bca..90f0831da 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -4,14 +4,12 @@
** See Copyright Notice in mruby.h
*/
+#include <ctype.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/proc.h"
#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "error.h"
-#include <ctype.h>
typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
@@ -48,11 +46,10 @@ iv_new(mrb_state *mrb)
iv_tbl *t;
t = mrb_malloc(mrb, sizeof(iv_tbl));
- if (t) {
- t->size = 0;
- t->rootseg = NULL;
- t->last_len = 0;
- }
+ t->size = 0;
+ t->rootseg = NULL;
+ t->last_len = 0;
+
return t;
}
@@ -118,7 +115,6 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
else {
t->rootseg = seg;
}
- return;
}
/*
@@ -293,8 +289,8 @@ iv_free(mrb_state *mrb, iv_tbl *t)
#define MRB_IVHASH_INIT_SIZE 8
#endif
-KHASH_DECLARE(iv, mrb_sym, mrb_value, 1)
-KHASH_DEFINE(iv, mrb_sym, mrb_value, 1, kh_int_hash_func, kh_int_hash_equal)
+KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE)
+KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal)
typedef struct iv_tbl {
khash_t(iv) h;
@@ -312,7 +308,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
khash_t(iv) *h = &t->h;
khiter_t k;
- k = kh_put(iv, h, sym);
+ k = kh_put(iv, mrb, h, sym);
kh_value(h, k) = val;
}
@@ -322,7 +318,7 @@ iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
khash_t(iv) *h = &t->h;
khiter_t k;
- k = kh_get(iv, h, sym);
+ k = kh_get(iv, mrb, h, sym);
if (k != kh_end(h)) {
if (vp) *vp = kh_value(h, k);
return TRUE;
@@ -337,10 +333,10 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
khiter_t k;
if (h) {
- k = kh_get(iv, h, sym);
+ k = kh_get(iv, mrb, h, sym);
if (k != kh_end(h)) {
mrb_value val = kh_value(h, k);
- kh_del(iv, h, k);
+ kh_del(iv, mrb, h, k);
if (vp) *vp = val;
return TRUE;
}
@@ -361,7 +357,7 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p);
if (n > 0) return FALSE;
if (n < 0) {
- kh_del(iv, h, k);
+ kh_del(iv, mrb, h, k);
}
}
}
@@ -372,10 +368,12 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
static size_t
iv_size(mrb_state *mrb, iv_tbl *t)
{
- khash_t(iv) *h = &t->h;
+ khash_t(iv) *h;
- if (!h) return 0;
- return kh_size(h);
+ if (t && (h = &t->h)) {
+ return kh_size(h);
+ }
+ return 0;
}
static iv_tbl*
@@ -387,7 +385,7 @@ iv_copy(mrb_state *mrb, iv_tbl *t)
static void
iv_free(mrb_state *mrb, iv_tbl *t)
{
- kh_destroy(iv, &t->h);
+ kh_destroy(iv, mrb, &t->h);
}
#endif
@@ -563,20 +561,28 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value str = *(mrb_value*)p;
const char *s;
- size_t len;
+ mrb_int len;
+ mrb_value ins;
+ char *sp = RSTRING_PTR(str);
/* need not to show internal data */
- if (RSTRING_PTR(str)[0] == '-') { /* first element */
- RSTRING_PTR(str)[0] = '#';
- mrb_str_cat(mrb, str, " ", 1);
+ if (sp[0] == '-') { /* first element */
+ sp[0] = '#';
+ mrb_str_cat_lit(mrb, str, " ");
}
else {
- mrb_str_cat(mrb, str, ", ", 2);
+ mrb_str_cat_lit(mrb, str, ", ");
}
s = mrb_sym2name_len(mrb, sym, &len);
mrb_str_cat(mrb, str, s, len);
- mrb_str_cat(mrb, str, "=", 1);
- mrb_str_append(mrb, str, mrb_inspect(mrb, v));
+ mrb_str_cat_lit(mrb, str, "=");
+ if (mrb_type(v) == MRB_TT_OBJECT) {
+ ins = mrb_any_to_s(mrb, v);
+ }
+ else {
+ ins = mrb_inspect(mrb, v);
+ }
+ mrb_str_append(mrb, str, ins);
return 0;
}
@@ -590,13 +596,13 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
mrb_value str = mrb_str_buf_new(mrb, 30);
- mrb_str_buf_cat(mrb, str, "-<", 2);
- mrb_str_cat2(mrb, str, cn);
- mrb_str_cat(mrb, str, ":", 1);
+ mrb_str_cat_lit(mrb, str, "-<");
+ mrb_str_cat_cstr(mrb, str, cn);
+ mrb_str_cat_lit(mrb, str, ":");
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));
iv_foreach(mrb, t, inspect_i, &str);
- mrb_str_cat(mrb, str, ">", 1);
+ mrb_str_cat_lit(mrb, str, ">");
return str;
}
return mrb_any_to_s(mrb, mrb_obj_value(obj));
@@ -635,7 +641,7 @@ iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
@@ -679,7 +685,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
@@ -750,7 +756,7 @@ mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
}
void
-mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v)
+mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
{
struct RClass * cls = c;
@@ -817,24 +823,7 @@ mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
struct RClass *c = mrb->c->ci->proc->target_class;
if (!c) c = mrb->c->ci->target_class;
- while (c) {
- if (c->iv) {
- iv_tbl *t = c->iv;
-
- if (iv_get(mrb, t, sym, NULL)) {
- mrb_write_barrier(mrb, (struct RBasic*)c);
- iv_put(mrb, t, sym, v);
- return;
- }
- }
- c = c->super;
- }
- c = mrb->c->ci->target_class;
- if (!c->iv) {
- c->iv = iv_new(mrb);
- }
- mrb_write_barrier(mrb, (struct RBasic*)c);
- iv_put(mrb, c->iv, sym, v);
+ mrb_mod_cv_set(mrb, c, sym, v);
}
mrb_bool
@@ -868,7 +857,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
mrb_value v;
iv_tbl *t;
mrb_bool retry = 0;
- mrb_sym cm;
+ mrb_value name;
L_RETRY:
while (c) {
@@ -884,19 +873,8 @@ L_RETRY:
retry = 1;
goto L_RETRY;
}
- c = base;
- cm = mrb_intern2(mrb, "const_missing", 13);
- while (c) {
- if (mrb_respond_to(mrb, mrb_obj_value(c), cm)) {
- mrb_value name = mrb_symbol_value(sym);
- return mrb_funcall_argv(mrb, mrb_obj_value(c), cm, 1, &name);
- }
- c = c->super;
- }
- mrb_name_error(mrb, sym, "uninitialized constant %S",
- mrb_sym2str(mrb, sym));
- /* not reached */
- return mrb_nil_value();
+ name = mrb_symbol_value(sym);
+ return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name);
}
mrb_value
@@ -971,11 +949,11 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
mrb_value ary;
const char* s;
- size_t len;
+ mrb_int len;
ary = *(mrb_value*)p;
s = mrb_sym2name_len(mrb, sym, &len);
- if (len > 1 && ISUPPER(s[0])) {
+ if (len >= 1 && ISUPPER(s[0])) {
mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
}
return 0;
@@ -1032,6 +1010,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
iv_put(mrb, t, sym, v);
}
+void
+mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
+{
+ if (!mrb->globals) {
+ return;
+ }
+ iv_del(mrb, mrb->globals, sym, NULL);
+}
+
static int
gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
@@ -1067,7 +1054,7 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self)
buf[2] = 0;
for (i = 1; i <= 9; ++i) {
buf[1] = (char)(i + '0');
- mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern2(mrb, buf, 2)));
+ mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2)));
}
return ary;
}
@@ -1130,7 +1117,7 @@ mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer)
{
mrb_value name;
- name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern2(mrb, "__classid__", 11));
+ name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__classid__"));
if (mrb_nil_p(name)) {
if (!outer) return 0;
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 000000000..7aac44d62
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,13 @@
+#include "mruby.h"
+#include "mruby/variable.h"
+
+void
+mrb_init_version(mrb_state* mrb)
+{
+ mrb_define_global_const(mrb, "RUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_RUBY_VERSION));
+ mrb_define_global_const(mrb, "RUBY_ENGINE", mrb_str_new_lit(mrb, MRUBY_RUBY_ENGINE));
+ mrb_define_global_const(mrb, "MRUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_VERSION));
+ mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE));
+ mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION));
+ mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT));
+}
diff --git a/src/vm.c b/src/vm.c
index 4d99ad413..5b9a7bf65 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -4,23 +4,22 @@
** See Copyright Notice in mruby.h
*/
-#include <string.h>
-#include <setjmp.h>
#include <stddef.h>
#include <stdarg.h>
+#include <math.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/hash.h"
#include "mruby/irep.h"
-#include "mruby/numeric.h"
#include "mruby/proc.h"
#include "mruby/range.h"
#include "mruby/string.h"
#include "mruby/variable.h"
-#include "error.h"
+#include "mruby/error.h"
#include "opcode.h"
#include "value_array.h"
+#include "mrb_throw.h"
#ifndef ENABLE_STDIO
#if defined(__cplusplus)
@@ -69,14 +68,23 @@ The value below allows about 60000 recursive calls in the simplest case. */
#define TO_STR(x) TO_STR_(x)
#define TO_STR_(x) #x
+#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)
+
static inline void
stack_clear(mrb_value *from, size_t count)
{
+#ifndef MRB_NAN_BOXING
const mrb_value mrb_value_zero = { { 0 } };
while (count-- > 0) {
*from++ = mrb_value_zero;
}
+#else
+ while (count-- > 0) {
+ SET_NIL_VALUE(*from);
+ from++;
+ }
+#endif
}
static inline void
@@ -102,6 +110,7 @@ stack_init(mrb_state *mrb)
c->ciend = c->cibase + CALLINFO_INIT_SIZE;
c->ci = c->cibase;
c->ci->target_class = mrb->object_class;
+ c->ci->stackent = c->stack;
}
static inline void
@@ -109,13 +118,15 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
{
mrb_callinfo *ci = mrb->c->cibase;
+ if (newbase == oldbase) return;
while (ci <= mrb->c->ci) {
struct REnv *e = ci->env;
- if (e && e->cioff >= 0) {
+ if (e && MRB_ENV_STACK_SHARED_P(e)) {
ptrdiff_t off = e->stack - oldbase;
e->stack = newbase + off;
}
+ ci->stackent = newbase + (ci->stackent - oldbase);
ci++;
}
}
@@ -123,48 +134,40 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */
static void
+stack_extend_alloc(mrb_state *mrb, int room)
+{
+ mrb_value *oldbase = mrb->c->stbase;
+ int size = mrb->c->stend - mrb->c->stbase;
+ int off = mrb->c->stack - mrb->c->stbase;
+
+ /* Use linear stack growth.
+ It is slightly slower than doubling the stack space,
+ but it saves memory on small devices. */
+ if (room <= size)
+ size += MRB_STACK_GROWTH;
+ else
+ size += room;
+
+ mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+ mrb->c->stack = mrb->c->stbase + off;
+ mrb->c->stend = mrb->c->stbase + size;
+ envadjust(mrb, oldbase, mrb->c->stbase);
+ /* Raise an exception if the new stack size will be too large,
+ to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
+ if (size > MRB_STACK_MAX) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "stack level too deep. (limit=" TO_STR(MRB_STACK_MAX) ")");
+ }
+}
+
+static inline void
stack_extend(mrb_state *mrb, int room, int keep)
{
if (mrb->c->stack + room >= mrb->c->stend) {
- int size, off;
-
- mrb_value *oldbase = mrb->c->stbase;
-
- size = mrb->c->stend - mrb->c->stbase;
- off = mrb->c->stack - mrb->c->stbase;
-
- /* do not leave uninitialized malloc region */
- if (keep > size) keep = size;
-
- /* Use linear stack growth.
- It is slightly slower than doubling thestack space,
- but it saves memory on small devices. */
- if (room <= size)
- size += MRB_STACK_GROWTH;
- else
- size += room;
-
- mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
- mrb->c->stack = mrb->c->stbase + off;
- mrb->c->stend = mrb->c->stbase + size;
- envadjust(mrb, oldbase, mrb->c->stbase);
- /* Raise an exception if the new stack size will be too large,
- to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
- if (size > MRB_STACK_MAX) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "stack level too deep. (limit=" TO_STR(MRB_STACK_MAX) ")");
- }
+ stack_extend_alloc(mrb, room);
}
-
if (room > keep) {
-#ifndef MRB_NAN_BOXING
+ /* do not leave uninitialized malloc region */
stack_clear(&(mrb->c->stack[keep]), room - keep);
-#else
- struct mrb_context *c = mrb->c;
- int i;
- for (i=keep; i<room; i++) {
- SET_NIL_VALUE(c->stack[i]);
- }
-#endif
}
}
@@ -185,7 +188,7 @@ is_strict(mrb_state *mrb, struct REnv *e)
{
int cioff = e->cioff;
- if (cioff >= 0 && mrb->c->cibase[cioff].proc &&
+ if (MRB_ENV_STACK_SHARED_P(e) && mrb->c->cibase[cioff].proc &&
MRB_PROC_STRICT_P(mrb->c->cibase[cioff].proc)) {
return TRUE;
}
@@ -205,6 +208,9 @@ top_env(mrb_state *mrb, struct RProc *proc)
return e;
}
+#define CI_ACC_SKIP -1
+#define CI_ACC_DIRECT -2
+
static mrb_callinfo*
cipush(mrb_state *mrb)
{
@@ -226,6 +232,9 @@ cipush(mrb_state *mrb)
ci->eidx = eidx;
ci->ridx = ridx;
ci->env = 0;
+ ci->pc = 0;
+ ci->err = 0;
+
return ci;
}
@@ -236,10 +245,10 @@ cipop(mrb_state *mrb)
if (c->ci->env) {
struct REnv *e = c->ci->env;
- size_t len = (size_t)e->flags;
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
- e->cioff = -1;
+ MRB_ENV_UNSHARE_STACK(e);
stack_copy(p, e->stack, len);
e->stack = p;
}
@@ -257,10 +266,12 @@ ecall(mrb_state *mrb, int i)
p = mrb->c->ensure[i];
if (!p) return;
+ if (mrb->c->ci->eidx > i)
+ mrb->c->ci->eidx = i;
ci = cipush(mrb);
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
- ci->acc = -1;
+ ci->acc = CI_ACC_SKIP;
ci->argc = 0;
ci->proc = p;
ci->nregs = p->body.irep->nregs;
@@ -312,28 +323,29 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, int argc, ...)
}
mrb_value
-mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_value *argv, mrb_value blk)
+mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, const mrb_value *argv, mrb_value blk)
{
mrb_value val;
if (!mrb->jmp) {
- jmp_buf c_jmp;
+ struct mrb_jmpbuf c_jmp;
mrb_callinfo *old_ci = mrb->c->ci;
- if (setjmp(c_jmp) != 0) { /* error */
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ /* recursive call */
+ val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
+ mrb->jmp = 0;
+ }
+ MRB_CATCH(&c_jmp) { /* error */
while (old_ci != mrb->c->ci) {
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
mrb->jmp = 0;
val = mrb_obj_value(mrb->exc);
}
- else {
- mrb->jmp = &c_jmp;
- /* recursive call */
- val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
- mrb->jmp = 0;
- }
+ MRB_END_EXC(&c_jmp);
}
else {
struct RProc *p;
@@ -353,23 +365,22 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
p = mrb_method_search_vm(mrb, &c, mid);
if (!p) {
undef = mid;
- mid = mrb_intern2(mrb, "method_missing", 14);
+ mid = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, mid);
n++; argc++;
}
ci = cipush(mrb);
ci->mid = mid;
ci->proc = p;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = argc;
- ci->target_class = p->target_class;
+ ci->target_class = c;
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
}
else {
ci->nregs = p->body.irep->nregs + n;
}
- ci->acc = -1;
mrb->c->stack = mrb->c->stack + n;
stack_extend(mrb, ci->nregs, 0);
@@ -385,12 +396,15 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
if (MRB_PROC_CFUNC_P(p)) {
int ai = mrb_gc_arena_save(mrb);
+
+ ci->acc = CI_ACC_DIRECT;
val = p->body.func(mrb, self);
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
mrb_gc_arena_restore(mrb, ai);
}
else {
+ ci->acc = CI_ACC_SKIP;
val = mrb_run(mrb, p, self);
}
}
@@ -399,13 +413,81 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
}
mrb_value
-mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_value *argv)
+mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, const mrb_value *argv)
{
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
+/* 15.3.1.3.4 */
+/* 15.3.1.3.44 */
+/*
+ * call-seq:
+ * obj.send(symbol [, args...]) -> obj
+ * obj.__send__(symbol [, args...]) -> obj
+ *
+ * Invokes the method identified by _symbol_, passing it any
+ * arguments specified. You can use <code>__send__</code> if the name
+ * +send+ clashes with an existing method in _obj_.
+ *
+ * class Klass
+ * def hello(*args)
+ * "Hello " + args.join(' ')
+ * end
+ * end
+ * k = Klass.new
+ * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
+ */
mrb_value
-mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c)
+mrb_f_send(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym name;
+ mrb_value block, *argv, *regs;
+ int argc, i, len;
+ struct RProc *p;
+ struct RClass *c;
+ mrb_callinfo *ci;
+
+ mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
+
+ c = mrb_class(mrb, self);
+ p = mrb_method_search_vm(mrb, &c, name);
+
+ if (!p) { /* call method_mising */
+ return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
+ }
+
+ ci = mrb->c->ci;
+ ci->mid = name;
+ ci->target_class = c;
+ ci->proc = p;
+ regs = mrb->c->stack+1;
+ /* remove first symbol from arguments */
+ if (ci->argc >= 0) {
+ for (i=0,len=ci->argc; i<len; i++) {
+ regs[i] = regs[i+1];
+ }
+ ci->argc--;
+ }
+ else { /* variable length arguments */
+ mrb_ary_shift(mrb, regs[0]);
+ }
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+mrb_value
+mrb_yield_with_class(mrb_state *mrb, mrb_value b, int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
{
struct RProc *p;
mrb_sym mid = mrb->c->ci->mid;
@@ -420,7 +502,7 @@ mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_v
ci = cipush(mrb);
ci->mid = mid;
ci->proc = p;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = argc;
ci->target_class = c;
if (MRB_PROC_CFUNC_P(p)) {
@@ -429,7 +511,7 @@ mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_v
else {
ci->nregs = p->body.irep->nregs + 1;
}
- ci->acc = -1;
+ ci->acc = CI_ACC_SKIP;
mrb->c->stack = mrb->c->stack + n;
stack_extend(mrb, ci->nregs, 0);
@@ -441,7 +523,7 @@ mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_v
if (MRB_PROC_CFUNC_P(p)) {
val = p->body.func(mrb, self);
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
else {
@@ -451,11 +533,11 @@ mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_v
}
mrb_value
-mrb_yield_argv(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv)
+mrb_yield_argv(mrb_state *mrb, mrb_value b, int argc, const mrb_value *argv)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_internal(mrb, b, argc, argv, mrb->c->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
}
mrb_value
@@ -463,7 +545,7 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_internal(mrb, b, 1, &arg, mrb->c->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
}
typedef enum {
@@ -484,7 +566,7 @@ localjump_error(mrb_state *mrb, localjump_error_kind kind)
msg = mrb_str_buf_new(mrb, sizeof(lead) + 7);
mrb_str_buf_cat(mrb, msg, lead, sizeof(lead) - 1);
mrb_str_buf_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
- exc = mrb_exc_new3(mrb, E_LOCALJUMP_ERROR, msg);
+ exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
mrb->exc = mrb_obj_ptr(exc);
}
@@ -503,17 +585,19 @@ argnum_error(mrb_state *mrb, int num)
str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
}
- exc = mrb_exc_new3(mrb, E_ARGUMENT_ERROR, str);
+ exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
mrb->exc = mrb_obj_ptr(exc);
}
+#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
+#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0;
#ifdef ENABLE_DEBUG
-#define CODE_FETCH_HOOK(mrb, irep, pc, regs) ((mrb)->code_fetch_hook ? (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)) : NULL)
+#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
#else
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
#endif
-#ifdef __GNUC__
+#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
#define DIRECT_THREADED
#endif
@@ -542,7 +626,7 @@ void mrb_gv_val_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
#define CALL_MAXARGS 127
mrb_value
-mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
+mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
/* mrb_assert(mrb_proc_cfunc_p(proc)) */
mrb_irep *irep = proc->body.irep;
@@ -552,8 +636,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
mrb_value *regs = NULL;
mrb_code i;
int ai = mrb_gc_arena_save(mrb);
- jmp_buf *prev_jmp = (jmp_buf *)mrb->jmp;
- jmp_buf c_jmp;
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
#ifdef DIRECT_THREADED
static void *optable[] = {
@@ -580,17 +664,20 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
};
#endif
+ mrb_bool exc_catched = FALSE;
+RETRY_TRY_BLOCK:
- if (setjmp(c_jmp) == 0) {
- mrb->jmp = &c_jmp;
- }
- else {
+ MRB_TRY(&c_jmp) {
+
+ if (exc_catched) {
+ exc_catched = FALSE;
goto L_RAISE;
}
+ mrb->jmp = &c_jmp;
if (!mrb->c->stack) {
stack_init(mrb);
}
- stack_extend(mrb, irep->nregs, irep->nregs);
+ stack_extend(mrb, irep->nregs, stack_keep);
mrb->c->ci->proc = proc;
mrb->c->ci->nregs = irep->nregs + 1;
regs = mrb->c->stack;
@@ -610,7 +697,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
- regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+ regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
NEXT;
}
@@ -682,7 +769,9 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETCV) {
/* A B R(A) := ivget(Sym(B)) */
+ ERR_PC_SET(mrb, pc);
regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
+ ERR_PC_CLR(mrb);
NEXT;
}
@@ -694,7 +783,13 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETCONST) {
/* A B R(A) := constget(Sym(B)) */
- regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+ mrb_value val;
+
+ ERR_PC_SET(mrb, pc);
+ val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+ ERR_PC_CLR(mrb);
+ regs = mrb->c->stack;
+ regs[GETARG_A(i)] = val;
NEXT;
}
@@ -706,9 +801,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_GETMCNST) {
/* A B C R(A) := R(C)::Sym(B) */
+ mrb_value val;
int a = GETARG_A(i);
- regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
+ ERR_PC_SET(mrb, pc);
+ val = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
+ ERR_PC_CLR(mrb);
+ regs = mrb->c->stack;
+ regs[a] = val;
NEXT;
}
@@ -814,7 +914,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* Bx ensure_push(SEQ[Bx]) */
struct RProc *p;
- p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
+ p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
/* push ensure_stack */
if (mrb->c->esize <= mrb->c->ci->eidx) {
if (mrb->c->esize == 0) mrb->c->esize = 16;
@@ -822,19 +922,20 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize);
}
mrb->c->ensure[mrb->c->ci->eidx++] = p;
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_EPOP) {
/* A A.times{ensure_pop().call} */
- int n;
int a = GETARG_A(i);
+ mrb_callinfo *ci = mrb->c->ci;
+ int n, eidx = ci->eidx;
- for (n=0; n<a; n++) {
- ecall(mrb, --mrb->c->ci->eidx);
+ for (n=0; n<a && eidx > ci[-1].eidx; n++) {
+ ecall(mrb, --eidx);
+ ARENA_RESTORE(mrb, ai);
}
- mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -875,7 +976,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
if (!m) {
mrb_value sym = mrb_symbol_value(mid);
- mid = mrb_intern2(mrb, "method_missing", 14);
+ mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
@@ -890,7 +991,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci = cipush(mrb);
ci->mid = mid;
ci->proc = m;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
if (n == CALL_MAXARGS) {
ci->argc = -1;
}
@@ -925,12 +1026,13 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci = mrb->c->ci;
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
- irep = ci[-1].proc->body.irep;
+ proc = ci[-1].proc;
+ irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
}
}
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
+ regs = mrb->c->stack = ci->stackent;
pc = ci->pc;
cipop(mrb);
JUMP;
@@ -985,7 +1087,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
+ regs = mrb->c->stack = ci->stackent;
regs[ci->acc] = recv;
pc = ci->pc;
cipop(mrb);
@@ -1032,7 +1134,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
- mid = mrb_intern2(mrb, "method_missing", 14);
+ mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
@@ -1047,14 +1149,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci = cipush(mrb);
ci->mid = mid;
ci->proc = m;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
if (n == CALL_MAXARGS) {
ci->argc = -1;
}
else {
ci->argc = n;
}
- ci->target_class = m->target_class;
+ ci->target_class = c;
ci->pc = pc + 1;
/* prepare stack */
@@ -1066,7 +1168,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
- regs = mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ regs = mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
NEXT;
}
@@ -1107,8 +1209,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
struct REnv *e = uvenv(mrb, lv-1);
if (!e) {
mrb_value exc;
- static const char m[] = "super called outside of method";
- exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, sizeof(m) - 1);
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
@@ -1140,7 +1241,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
rest->len = m1+len+m2;
}
regs[a+1] = stack[m1+r+m2];
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1245,8 +1346,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
L_RAISE:
ci = mrb->c->ci;
- mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern2(mrb, "lastpc", 6), mrb_voidp_value(mrb, pc));
- mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->c->cibase));
+ mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, pc));
+ mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->c->cibase));
eidx = ci->eidx;
if (ci == mrb->c->cibase) {
if (ci->ridx == 0) goto L_STOP;
@@ -1258,27 +1359,39 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
while (ci[0].ridx == ci[-1].ridx) {
cipop(mrb);
ci = mrb->c->ci;
- mrb->c->stack = mrb->c->stbase + ci[1].stackidx;
- if (ci[1].acc < 0 && prev_jmp) {
+ mrb->c->stack = ci[1].stackent;
+ if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
mrb->jmp = prev_jmp;
- mrb_longjmp(mrb);
+ MRB_THROW(prev_jmp);
}
- while (eidx > ci->eidx) {
- ecall(mrb, --eidx);
+ if (ci > mrb->c->cibase) {
+ while (eidx > ci[-1].eidx) {
+ ecall(mrb, --eidx);
+ }
}
- if (ci == mrb->c->cibase) {
+ else if (ci == mrb->c->cibase) {
if (ci->ridx == 0) {
- regs = mrb->c->stack = mrb->c->stbase;
- goto L_STOP;
+ if (mrb->c == mrb->root_c) {
+ regs = mrb->c->stack = mrb->c->stbase;
+ goto L_STOP;
+ }
+ else {
+ struct mrb_context *c = mrb->c;
+
+ mrb->c = c->prev;
+ c->prev = NULL;
+ goto L_RAISE;
+ }
}
break;
}
}
L_RESCUE:
- irep = ci->proc->body.irep;
+ proc = ci->proc;
+ irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- regs = mrb->c->stack = mrb->c->stbase + ci[1].stackidx;
+ regs = mrb->c->stack = ci[1].stackent;
pc = mrb->c->rescue[--ci->ridx];
}
else {
@@ -1288,11 +1401,11 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
switch (GETARG_B(i)) {
case OP_R_RETURN:
- // Fall through to OP_R_NORMAL otherwise
+ /* Fall through to OP_R_NORMAL otherwise */
if (proc->env && !MRB_PROC_STRICT_P(proc)) {
struct REnv *e = top_env(mrb, proc);
- if (e->cioff < 0) {
+ if (!MRB_ENV_STACK_SHARED_P(e)) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
@@ -1311,21 +1424,29 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
goto L_RAISE;
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
- mrb_value exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mrb_str_new(mrb, "double resume", 13));
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
/* automatic yield at the end */
mrb->c->status = MRB_FIBER_TERMINATED;
mrb->c = mrb->c->prev;
+ mrb->c->status = MRB_FIBER_RUNNING;
}
ci = mrb->c->ci;
break;
case OP_R_BREAK:
- if (proc->env->cioff < 0) {
+ if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
localjump_error(mrb, LOCALJUMP_ERROR_BREAK);
goto L_RAISE;
}
+ /* break from fiber block */
+ if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
+ struct mrb_context *c = mrb->c;
+
+ mrb->c = c->prev;
+ c->prev = NULL;
+ }
ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
break;
default:
@@ -1338,8 +1459,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
cipop(mrb);
acc = ci->acc;
pc = ci->pc;
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
- if (acc < 0) {
+ regs = mrb->c->stack = ci->stackent;
+ if (acc == CI_ACC_SKIP) {
mrb->jmp = prev_jmp;
return v;
}
@@ -1370,7 +1491,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
if (!m) {
mrb_value sym = mrb_symbol_value(mid);
- mid = mrb_intern2(mrb, "method_missing", 14);
+ mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
@@ -1384,7 +1505,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* replace callinfo */
ci = mrb->c->ci;
ci->mid = mid;
- ci->target_class = m->target_class;
+ ci->target_class = c;
if (n == CALL_MAXARGS) {
ci->argc = -1;
}
@@ -1514,7 +1635,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
default:
goto L_SEND;
}
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1681,6 +1802,11 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
default:
goto L_SEND;
}
+#ifdef MRB_NAN_BOXING
+ if (isnan(regs[a].attr_f)) {
+ regs[a] = mrb_float_value(mrb, regs[a].attr_f);
+ }
+#endif
NEXT;
}
@@ -1831,7 +1957,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_ARRAY) {
/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), &regs[GETARG_B(i)]);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1839,7 +1965,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* A B mrb_ary_concat(R(A),R(B)) */
mrb_ary_concat(mrb, regs[GETARG_A(i)],
mrb_ary_splat(mrb, regs[GETARG_B(i)]));
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1911,14 +2037,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
}
}
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_STRING) {
/* A Bx R(A) := str_new(Lit(Bx)) */
- regs[GETARG_A(i)] = mrb_str_literal(mrb, pool[GETARG_Bx(i)]);
- mrb_gc_arena_restore(mrb, ai);
+ regs[GETARG_A(i)] = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1940,7 +2066,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
b+=2;
}
regs[GETARG_A(i)] = hash;
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1950,14 +2076,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
int c = GETARG_c(i);
if (c & OP_L_CAPTURE) {
- p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
+ p = mrb_closure_new(mrb, irep->reps[GETARG_b(i)]);
}
else {
- p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
+ p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]);
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
regs[GETARG_A(i)] = mrb_obj_value(p);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1981,7 +2107,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
c = mrb_vm_define_class(mrb, base, super, id);
regs[a] = mrb_obj_value(c);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -1998,7 +2124,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
c = mrb_vm_define_module(mrb, base, id);
regs[a] = mrb_obj_value(c);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2014,14 +2140,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci->pc = pc + 1;
ci->acc = a;
ci->mid = 0;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = 0;
ci->target_class = mrb_class_ptr(recv);
/* prepare stack */
mrb->c->stack += a;
- p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
+ p = mrb_proc_new(mrb, irep->reps[GETARG_Bx(i)]);
p->target_class = ci->target_class;
ci->proc = p;
@@ -2030,7 +2156,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
- regs = mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ regs = mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
NEXT;
}
@@ -2052,22 +2178,21 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
struct RClass *c = mrb_class_ptr(regs[a]);
mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_SCLASS) {
/* A B R(A) := R(B).singleton_class */
regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_TCLASS) {
/* A B R(A) := target_class */
if (!mrb->c->ci->target_class) {
- static const char msg[] = "no target class or module";
- mrb_value exc = mrb_exc_new(mrb, E_TYPE_ERROR, msg, sizeof(msg) - 1);
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
@@ -2079,17 +2204,21 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* A B C R(A) := range_new(R(B),R(B+1),C) */
int b = GETARG_B(i);
regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
- mrb_gc_arena_restore(mrb, ai);
+ ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_DEBUG) {
/* A debug print R(A),R(B),R(C) */
+#ifdef ENABLE_DEBUG
+ mrb->debug_op_hook(mrb, irep, pc, regs);
+#else
#ifdef ENABLE_STDIO
printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
#else
abort();
#endif
+#endif
NEXT;
}
@@ -2103,6 +2232,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ecall(mrb, n);
}
}
+ ERR_PC_CLR(mrb);
mrb->jmp = prev_jmp;
if (mrb->exc) {
return mrb_obj_value(mrb->exc);
@@ -2112,24 +2242,51 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_ERR) {
/* Bx raise RuntimeError with message Lit(Bx) */
- mrb_value msg = pool[GETARG_Bx(i)];
+ mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
mrb_value exc;
if (GETARG_A(i) == 0) {
- exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, msg);
+ exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg);
}
else {
- exc = mrb_exc_new3(mrb, E_LOCALJUMP_ERROR, msg);
+ exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
}
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
}
END_DISPATCH;
+
+ }
+ MRB_CATCH(&c_jmp) {
+ exc_catched = TRUE;
+ goto RETRY_TRY_BLOCK;
+ }
+ MRB_END_EXC(&c_jmp);
}
-void
-mrb_longjmp(mrb_state *mrb)
+mrb_value
+mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
- longjmp(*(jmp_buf*)mrb->jmp, 1);
+ return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+}
+
+mrb_value
+mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+{
+ mrb_callinfo *ci;
+ mrb_value v;
+
+ if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
+ return mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ }
+ ci = cipush(mrb);
+ ci->acc = CI_ACC_SKIP;
+ ci->eidx = 0;
+ ci->ridx = 0;
+ ci->target_class = mrb->object_class;
+ v = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ cipop(mrb);
+
+ return v;
}