diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 511 | ||||
| -rw-r--r-- | src/backtrace.c | 160 | ||||
| -rw-r--r-- | src/class.c | 537 | ||||
| -rw-r--r-- | src/codegen.c | 581 | ||||
| -rw-r--r-- | src/crc.c | 13 | ||||
| -rw-r--r-- | src/debug.c | 215 | ||||
| -rw-r--r-- | src/dump.c | 596 | ||||
| -rw-r--r-- | src/error.c | 88 | ||||
| -rw-r--r-- | src/error.h | 22 | ||||
| -rw-r--r-- | src/etc.c | 88 | ||||
| -rw-r--r-- | src/gc.c | 162 | ||||
| -rw-r--r-- | src/hash.c | 692 | ||||
| -rw-r--r-- | src/init.c | 2 | ||||
| -rw-r--r-- | src/kernel.c | 205 | ||||
| -rw-r--r-- | src/load.c | 720 | ||||
| -rw-r--r-- | src/mrb_throw.h | 41 | ||||
| -rw-r--r-- | src/mruby_core.rake | 62 | ||||
| -rw-r--r-- | src/node.h | 208 | ||||
| -rw-r--r-- | src/numeric.c | 425 | ||||
| -rw-r--r-- | src/object.c | 72 | ||||
| -rw-r--r-- | src/opcode.h | 6 | ||||
| -rw-r--r-- | src/parse.y | 6492 | ||||
| -rw-r--r-- | src/pool.c | 9 | ||||
| -rw-r--r-- | src/print.c | 18 | ||||
| -rw-r--r-- | src/proc.c | 26 | ||||
| -rw-r--r-- | src/range.c | 50 | ||||
| -rw-r--r-- | src/re.h | 3 | ||||
| -rw-r--r-- | src/state.c | 131 | ||||
| -rw-r--r-- | src/string.c | 653 | ||||
| -rw-r--r-- | src/symbol.c | 108 | ||||
| -rw-r--r-- | src/variable.c | 127 | ||||
| -rw-r--r-- | src/version.c | 13 | ||||
| -rw-r--r-- | src/vm.c | 453 |
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); } @@ -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" @@ -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; } @@ -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(§ion_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 */ @@ -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)); +} @@ -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), ®s[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; } |
