diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 38 | ||||
| -rw-r--r-- | src/class.c | 346 | ||||
| -rw-r--r-- | src/codegen.c | 2721 | ||||
| -rw-r--r-- | src/dump.c | 11 | ||||
| -rw-r--r-- | src/error.c | 9 | ||||
| -rw-r--r-- | src/etc.c | 14 | ||||
| -rw-r--r-- | src/fmt_fp.c | 9 | ||||
| -rw-r--r-- | src/gc.c | 12 | ||||
| -rw-r--r-- | src/hash.c | 9 | ||||
| -rw-r--r-- | src/kernel.c | 33 | ||||
| -rw-r--r-- | src/keywords | 50 | ||||
| -rw-r--r-- | src/lex.def | 212 | ||||
| -rw-r--r-- | src/load.c | 2 | ||||
| -rw-r--r-- | src/mruby_core.rake | 63 | ||||
| -rw-r--r-- | src/node.h | 117 | ||||
| -rw-r--r-- | src/numeric.c | 23 | ||||
| -rw-r--r-- | src/object.c | 3 | ||||
| -rw-r--r-- | src/parse.y | 6420 | ||||
| -rw-r--r-- | src/print.c | 40 | ||||
| -rw-r--r-- | src/proc.c | 6 | ||||
| -rw-r--r-- | src/range.c | 4 | ||||
| -rw-r--r-- | src/state.c | 1 | ||||
| -rw-r--r-- | src/string.c | 115 | ||||
| -rw-r--r-- | src/variable.c | 4 | ||||
| -rw-r--r-- | src/version.c | 1 | ||||
| -rw-r--r-- | src/vm.c | 64 |
26 files changed, 509 insertions, 9818 deletions
diff --git a/src/array.c b/src/array.c index 48dc1ff10..2622ee528 100644 --- a/src/array.c +++ b/src/array.c @@ -19,7 +19,6 @@ static inline mrb_value ary_elt(mrb_value ary, mrb_int offset) { - if (RARRAY_LEN(ary) == 0) return mrb_nil_value(); if (offset < 0 || RARRAY_LEN(ary) <= offset) { return mrb_nil_value(); } @@ -88,15 +87,12 @@ array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals) { - mrb_value ary; - struct RArray *a; + struct RArray *a = ary_new_capa(mrb, size); - ary = mrb_ary_new_capa(mrb, size); - a = mrb_ary_ptr(ary); array_copy(a->ptr, vals, size); a->len = size; - return ary; + return mrb_obj_value(a); } MRB_API mrb_value @@ -293,18 +289,19 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int blen; mrb_get_args(mrb, "a", &ptr, &blen); - ary = mrb_ary_new_capa(mrb, a1->len + blen); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE - blen < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + a2 = ary_new_capa(mrb, a1->len + blen); array_copy(a2->ptr, a1->ptr, a1->len); array_copy(a2->ptr + a1->len, ptr, blen); a2->len = a1->len + blen; - return ary; + return mrb_obj_value(a2); } static void @@ -342,7 +339,6 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int times; @@ -351,9 +347,10 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); } if (times == 0) return mrb_ary_new(mrb); - - ary = mrb_ary_new_capa(mrb, a1->len * times); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE / times < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + a2 = ary_new_capa(mrb, a1->len * times); ptr = a2->ptr; while (times--) { array_copy(ptr, a1->ptr, a1->len); @@ -361,7 +358,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) a2->len += a1->len; } - return ary; + return mrb_obj_value(a2); } static mrb_value @@ -388,11 +385,8 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self) static mrb_value mrb_ary_reverse(mrb_state *mrb, mrb_value self) { - struct RArray *a = mrb_ary_ptr(self), *b; - mrb_value ary; + struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len); - ary = mrb_ary_new_capa(mrb, a->len); - b = mrb_ary_ptr(ary); if (a->len > 0) { mrb_value *p1, *p2, *e; @@ -404,7 +398,7 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self) } b->len = a->len; } - return ary; + return mrb_obj_value(b); } MRB_API void @@ -1036,7 +1030,7 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary) { mrb_value sep = mrb_nil_value(); - mrb_get_args(mrb, "|S", &sep); + mrb_get_args(mrb, "|S!", &sep); return mrb_ary_join(mrb, ary, sep); } @@ -1047,7 +1041,6 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); - if (mrb_immediate_p(ary2)) return mrb_false_value(); if (!mrb_array_p(ary2)) { return mrb_false_value(); } @@ -1063,7 +1056,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); - if (mrb_immediate_p(ary2)) return mrb_nil_value(); if (!mrb_array_p(ary2)) { return mrb_nil_value(); } diff --git a/src/class.c b/src/class.c index 3246564ec..c3c3e0b8f 100644 --- a/src/class.c +++ b/src/class.c @@ -76,7 +76,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->mt = 0; + sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { c = (struct RClass*)o; @@ -131,6 +131,19 @@ mrb_class_outer_module(mrb_state *mrb, struct RClass *c) return mrb_class_ptr(outer); } +static void +check_if_class_or_module(mrb_state *mrb, mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + return; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + } +} + static struct RClass* define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer) { @@ -160,6 +173,7 @@ mrb_define_module(mrb_state *mrb, const char *name) MRB_API struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { + check_if_class_or_module(mrb, outer); return define_module(mrb, id, mrb_class_ptr(outer)); } @@ -174,12 +188,20 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) } static struct RClass* +find_origin(struct RClass *c) +{ + MRB_CLASS_ORIGIN(c); + return c; +} + +static struct RClass* define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer) { struct RClass * c; if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); + MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", mrb_sym2str(mrb, name), @@ -198,7 +220,7 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { - mrb_warn(mrb, "no super class for `%S', Object assumed", mrb_sym2str(mrb, name)); + mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); } return define_class(mrb, name, super, mrb->object_class); } @@ -232,15 +254,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id else { s = 0; } - switch (mrb_type(outer)) { - case MRB_TT_CLASS: - case MRB_TT_SCLASS: - case MRB_TT_MODULE: - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", outer); - break; - } + check_if_class_or_module(mrb, outer); c = define_class(mrb, id, s, mrb_class_ptr(outer)); mrb_class_inherited(mrb, mrb_class_real(c->super), c); @@ -305,7 +319,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s #if 0 if (!super) { - mrb_warn(mrb, "no super class for `%S::%S', Object assumed", + mrb_warn(mrb, "no super class for '%S::%S', Object assumed", mrb_obj_value(outer), mrb_sym2str(mrb, id)); } #endif @@ -317,8 +331,10 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s MRB_API void mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) { - khash_t(mt) *h = c->mt; + khash_t(mt) *h; khiter_t k; + MRB_CLASS_ORIGIN(c); + h = c->mt; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); @@ -429,12 +445,12 @@ to_sym(mrb_state *mrb, mrb_value ss) ---------------------------------------------------------------------------------------------- o: Object [mrb_value] C: class/module [mrb_value] - S: String [mrb_value] - A: Array [mrb_value] - H: Hash [mrb_value] - s: String [char*,mrb_int] Receive two arguments. - z: String [char*] NUL terminated string. - a: Array [mrb_value*,mrb_int] Receive two arguments. + S: String [mrb_value] when ! follows, the value may be nil + A: Array [mrb_value] when ! follows, the value may be nil + H: Hash [mrb_value] when ! follows, the value may be nil + s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil + z: String [char*] NUL terminated string; z! gives NULL for nil + a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil f: Float [mrb_float] i: Integer [mrb_int] b: Boolean [mrb_bool] @@ -519,6 +535,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_str(mrb, *sp++); i++; @@ -530,6 +554,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_ary(mrb, *sp++); i++; @@ -541,6 +573,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_hash(mrb, *sp++); i++; @@ -555,6 +595,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, char**); pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *ps = NULL; + *pl = 0; + i++; + break; + } + } if (i < argc) { ss = to_str(mrb, *sp++); *ps = RSTRING_PTR(ss); @@ -569,6 +618,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps; ps = va_arg(ap, const char**); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *ps = NULL; + i++; + break; + } + } if (i < argc) { ss = to_str(mrb, *sp++); *ps = mrb_string_value_cstr(mrb, &ss); @@ -585,6 +642,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *pb = 0; + *pl = 0; + i++; + break; + } + } if (i < argc) { aa = to_ary(mrb, *sp++); a = mrb_ary_ptr(aa); @@ -670,6 +736,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) datap = va_arg(ap, void**); type = va_arg(ap, struct mrb_data_type const*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *datap = 0; + i++; + break; + } + } if (i < argc) { *datap = mrb_data_get_ptr(mrb, *sp++, type); ++i; @@ -753,47 +827,130 @@ boot_defclass(mrb_state *mrb, struct RClass *super) return c; } -MRB_API void -mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +static void +boot_initmod(mrb_state *mrb, struct RClass *mod) { - struct RClass *ins_pos; + mod->mt = kh_init(mt, mrb); +} + +static struct RClass* +include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) +{ + struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); + if (m->tt == MRB_TT_ICLASS) { + m = m->c; + } + MRB_CLASS_ORIGIN(m); + ic->iv = m->iv; + ic->mt = m->mt; + ic->super = super; + if (m->tt == MRB_TT_ICLASS) { + ic->c = m->c; + } else { + ic->c = m; + } + return ic; +} + +static int +include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) +{ + struct RClass *p, *ic; + void *klass_mt = find_origin(c)->mt; - ins_pos = c; while (m) { - struct RClass *p = c, *ic; int superclass_seen = 0; - if (c->mt && c->mt == m->mt) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); - } - while (p) { - if (c != p && p->tt == MRB_TT_CLASS) { - superclass_seen = 1; - } - else if (p->mt == m->mt) { - if (p->tt == MRB_TT_ICLASS && !superclass_seen) { - ins_pos = p; + if (m->flags & MRB_FLAG_IS_PREPENDED) + goto skip; + + if (klass_mt && klass_mt == m->mt) + return -1; + + p = c->super; + while(p) { + if (p->tt == MRB_TT_ICLASS) { + if (p->mt == m->mt) { + if (!superclass_seen) { + ins_pos = p; // move insert point + } + goto skip; } - goto skip; + } else if (p->tt == MRB_TT_CLASS) { + if (!search_super) break; + superclass_seen = 1; } p = p->super; } - ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); - if (m->tt == MRB_TT_ICLASS) { - ic->c = m->c; - } - else { - ic->c = m; - } - ic->mt = m->mt; - ic->iv = m->iv; - ic->super = ins_pos->super; + + ic = include_class_new(mrb, m, ins_pos->super); ins_pos->super = ic; - mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); + mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ins_pos->super); ins_pos = ic; skip: m = m->super; } + return 0; +} + +MRB_API void +mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + int changed = include_module_at(mrb, c, find_origin(c), m, 1); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); + } +} + +MRB_API void +mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + struct RClass *origin; + int changed = 0; + + if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); + origin->flags |= MRB_FLAG_IS_ORIGIN; + origin->super = c->super; + c->super = origin; + origin->mt = c->mt; + c->mt = kh_init(mt, mrb); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); + c->flags |= MRB_FLAG_IS_PREPENDED; + } + changed = include_module_at(mrb, c, c, m, 0); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected"); + } +} + +static mrb_value +mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod) +{ + mrb_value klass; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_get_args(mrb, "C", &klass); + mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + return mod; +} + +static mrb_value +mrb_mod_prepend(mrb_state *mrb, mrb_value klass) +{ + mrb_value *argv; + mrb_int argc, i; + + mrb_get_args(mrb, "*", &argv, &argc); + for (i=0; i<argc; i++) { + mrb_check_type(mrb, argv[i], MRB_TT_MODULE); + } + while (argc--) { + mrb_funcall(mrb, argv[argc], "prepend_features", 1, klass); + mrb_funcall(mrb, argv[argc], "prepended", 1, klass); + } + + return klass; } static mrb_value @@ -867,15 +1024,12 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); - result = mrb_ary_new(mrb); - mrb_ary_push(mrb, result, mrb_obj_value(c)); - c = c->super; while (c) { if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (c->tt != MRB_TT_SCLASS) { + else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -900,11 +1054,15 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + MRB_CLASS_ORIGIN(origin); result = mrb_ary_new(mrb); while (c) { - if (c->tt == MRB_TT_ICLASS) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + if (c != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } } c = c->super; } @@ -916,10 +1074,11 @@ static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; - - mrb_get_args(mrb, "&", &b); + struct RClass *m = mrb_class_ptr(mod); + boot_initmod(mrb, m); // bootstrap a newly initialized module + mrb_get_args(mrb, "|&", &b); if (!mrb_nil_p(b)) { - mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod)); + mrb_yield_with_class(mrb, b, 1, &mod, mod, m); } return mod; } @@ -1168,11 +1327,11 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * call-seq: * class.new(args, ...) -> obj * - * Calls <code>allocate</code> to create a new object of - * <i>class</i>'s class, then invokes that object's - * <code>initialize</code> method, passing it <i>args</i>. - * This is the method that ends up getting called whenever - * an object is constructed using .new. + * Creates a new object of <i>class</i>'s class, then + * invokes that object's <code>initialize</code> method, + * passing it <i>args</i>. This is the method that ends + * up getting called whenever an object is constructed using + * `.new`. * */ @@ -1236,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->super; + c = find_origin(c)->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->super; + c = find_origin(c)->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1256,6 +1415,31 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv) return mrb_bool_value(!mrb_test(cv)); } +void +mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) +{ + mrb_sym inspect; + mrb_value repr; + + 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, self); + } + else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { + repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, self); + } + } + else { + repr = mrb_any_to_s(mrb, self); + } + + mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", + mrb_sym2str(mrb, name), repr); +} + /* 15.3.1.3.30 */ /* * call-seq: @@ -1295,27 +1479,9 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod) mrb_sym name; mrb_value *a; mrb_int alen; - mrb_sym inspect; - mrb_value repr; mrb_get_args(mrb, "n*", &name, &a, &alen); - - 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) && mrb->c->ci - mrb->c->cibase < 64) { - repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0); - if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { - repr = mrb_any_to_s(mrb, mod); - } - } - else { - repr = mrb_any_to_s(mrb, mod); - } - - mrb_no_method_error(mrb, name, alen, a, "undefined method '%S' for %S", mrb_sym2str(mrb, name), repr); + mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); /* not reached */ return mrb_nil_value(); } @@ -1469,8 +1635,7 @@ MRB_API struct RClass* mrb_module_new(mrb_state *mrb) { struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); - m->mt = kh_init(mt, mrb); - + boot_initmod(mrb, m); return m; } @@ -1537,10 +1702,10 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: - mrb_str_append(mrb, str, mrb_inspect(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); break; default: - mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v)); break; } return mrb_str_cat_lit(mrb, str, ">"); @@ -1652,7 +1817,7 @@ check_cv_name_str(mrb_state *mrb, mrb_value 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); + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); } } @@ -1829,18 +1994,19 @@ static void remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) { struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = c->mt; + khash_t(mt) *h = find_origin(c)->mt; khiter_t k; if (h) { k = kh_get(mt, mrb, h, mid); if (k != kh_end(h)) { kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); return; } } - mrb_name_error(mrb, mid, "method `%S' not defined in %S", + mrb_name_error(mrb, mid, "method '%S' not defined in %S", mrb_sym2str(mrb, mid), mod); } @@ -2069,6 +2235,9 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ + mrb_define_method(mrb, mod, "prepend", mrb_mod_prepend, MRB_ARGS_ANY()); + mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "include", mrb_mod_include, MRB_ARGS_ANY()); /* 15.2.2.4.27 */ mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */ mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ @@ -2085,6 +2254,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); diff --git a/src/codegen.c b/src/codegen.c deleted file mode 100644 index 222dec9b6..000000000 --- a/src/codegen.c +++ /dev/null @@ -1,2721 +0,0 @@ -/* -** codegen.c - mruby code generator -** -** See Copyright Notice in mruby.h -*/ - -#include <ctype.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/proc.h" -#include "mruby/numeric.h" -#include "mruby/string.h" -#include "mruby/debug.h" -#include "node.h" -#include "mruby/opcode.h" -#include "mruby/re.h" -#include "mruby/throw.h" - -typedef mrb_ast_node node; -typedef struct mrb_parser_state parser_state; - -enum looptype { - LOOP_NORMAL, - LOOP_BLOCK, - LOOP_FOR, - LOOP_BEGIN, - LOOP_RESCUE, -}; - -struct loopinfo { - enum looptype type; - int pc1, pc2, pc3, acc; - int ensure_level; - struct loopinfo *prev; -}; - -typedef struct scope { - mrb_state *mrb; - mrb_pool *mpool; - struct mrb_jmpbuf jmp; - - struct scope *prev; - - node *lv; - - int sp; - int pc; - int lastlabel; - int ainfo:15; - mrb_bool mscope:1; - - struct loopinfo *loop; - int ensure_level; - char const *filename; - uint16_t lineno; - - mrb_code *iseq; - uint16_t *lines; - int icapa; - - mrb_irep *irep; - size_t pcapa; - size_t scapa; - size_t rcapa; - - uint16_t nlocals; - uint16_t nregs; - int ai; - - 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); -static void scope_finish(codegen_scope *s); -static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); -static void loop_break(codegen_scope *s, node *tree); -static void loop_pop(codegen_scope *s, int val); - -static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); -static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); - -static void codegen(codegen_scope *s, node *tree, int val); -static void raise_error(codegen_scope *s, const char *msg); - -static void -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 = tmp; - } -#ifdef ENABLE_STDIO - if (s->filename && s->lineno) { - fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); - } - else { - fprintf(stderr, "codegen error: %s\n", message); - } -#endif - MRB_THROW(&s->jmp); -} - -static void* -codegen_palloc(codegen_scope *s, size_t len) -{ - void *p = mrb_pool_alloc(s->mpool, len); - - if (!p) codegen_error(s, "pool memory allocation"); - return p; -} - -static void* -codegen_malloc(codegen_scope *s, size_t len) -{ - void *p = mrb_malloc_simple(s->mrb, len); - - if (!p) codegen_error(s, "mrb_malloc"); - return p; -} - -static void* -codegen_realloc(codegen_scope *s, void *p, size_t len) -{ - p = mrb_realloc_simple(s->mrb, p, len); - - if (!p && len > 0) codegen_error(s, "mrb_realloc"); - return p; -} - -static int -new_label(codegen_scope *s) -{ - s->lastlabel = s->pc; - return s->pc; -} - -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 = (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; - } - return s->pc++; -} - -#define NOVAL 0 -#define VAL 1 - -static mrb_bool -no_optimize(codegen_scope *s) -{ - if (s && s->parser && s->parser->no_optimize) - return TRUE; - return FALSE; -} - -static int -genop_peep(codegen_scope *s, mrb_code i, int val) -{ - /* peephole optimization */ - if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { - mrb_code i0 = s->iseq[s->pc-1]; - int c1 = GET_OPCODE(i); - int c0 = GET_OPCODE(i0); - - switch (c1) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_B(i)) { - /* skip useless OP_MOVE */ - return 0; - } - if (val) break; - switch (c0) { - case OP_MOVE: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { - /* skip swapping OP_MOVE */ - return 0; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->pc--; - return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); - } - 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 0; - } - break; - case OP_ARRAY: - case OP_HASH: - case OP_RANGE: - case OP_AREF: - 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 0; - } - break; - case OP_LOADSYM: - case OP_GETGLOBAL: - case OP_GETIV: - case OP_GETCV: - case OP_GETCONST: - case OP_GETSPECIAL: - case OP_LOADL: - 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 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 0; - } - break; - case OP_LOADNIL: - case OP_LOADSELF: - case OP_LOADT: - case OP_LOADF: - 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 0; - } - break; - default: - break; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETGLOBAL: - if (val) break; - 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 0; - } - } - break; - case OP_SETUPVAR: - if (val) break; - 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 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 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 0; - } - break; - case OP_RETURN: - switch (c0) { - case OP_RETURN: - return 0; - case OP_MOVE: - 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: - case OP_SETMCNST: - case OP_SETUPVAR: - case OP_SETGLOBAL: - s->pc--; - genop_peep(s, i0, NOVAL); - i0 = s->iseq[s->pc-1]; - 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)) { - s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); - return; - } - break; -#endif - default: - break; - } - break; - case OP_ADD: - case OP_SUB: - if (c0 == OP_LOADI) { - int c = GETARG_sBx(i0); - - if (c1 == OP_SUB) c = -c; - if (c > 127 || c < -127) break; - if (0 <= c) - 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 0; - } - case OP_STRCAT: - if (c0 == OP_STRING) { - mrb_value v = s->irep->pool[GETARG_Bx(i0)]; - - if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { - s->pc--; - 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; - } - } - return genop(s, i); -} - -static void -scope_error(codegen_scope *s) -{ - exit(EXIT_FAILURE); -} - -static inline void -dispatch(codegen_scope *s, int pc) -{ - int diff = s->pc - pc; - mrb_code i = s->iseq[pc]; - int c = GET_OPCODE(i); - - s->lastlabel = s->pc; - switch (c) { - case OP_JMP: - case OP_JMPIF: - case OP_JMPNOT: - case OP_ONERR: - break; - default: -#ifdef ENABLE_STDIO - fprintf(stderr, "bug: dispatch on non JMP op\n"); -#endif - scope_error(s); - break; - } - s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); -} - -static void -dispatch_linked(codegen_scope *s, int pc) -{ - mrb_code i; - int pos; - - if (!pc) return; - for (;;) { - i = s->iseq[pc]; - pos = GETARG_sBx(i); - dispatch(s, pc); - if (!pos) break; - pc = pos; - } -} - -#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) -static void -push_(codegen_scope *s) -{ - if (s->sp > 511) { - codegen_error(s, "too complex expression"); - } - s->sp++; - nregs_update; -} - -#define push() push_(s) -#define pop_(s) ((s)->sp--) -#define pop() pop_(s) -#define pop_n(n) (s->sp-=(n)) -#define cursp() (s->sp) - -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_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) - return i; - } - break; - case MRB_TT_FLOAT: - for (i=0; i<s->irep->plen; 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); - } - - 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; -} - -static inline int -new_msym(codegen_scope *s, mrb_sym sym) -{ - size_t i, len; - - mrb_assert(s->irep); - - len = s->irep->slen; - if (len > 256) len = 256; - for (i=0; i<len; i++) { - if (s->irep->syms[i] == sym) return i; - if (s->irep->syms[i] == 0) break; - } - if (i == 256) { - codegen_error(s, "too many symbols (max 256)"); - } - s->irep->syms[i] = sym; - if (i == s->irep->slen) s->irep->slen++; - return i; -} - -static inline int -new_sym(codegen_scope *s, mrb_sym sym) -{ - size_t i; - - for (i=0; i<s->irep->slen; i++) { - if (s->irep->syms[i] == sym) return i; - } - if (s->irep->slen > 125 && s->irep->slen < 256) { - s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536); - for (i = 0; i < 256 - s->irep->slen; i++) { - static const mrb_sym mrb_sym_zero = { 0 }; - s->irep->syms[i + s->irep->slen] = mrb_sym_zero; - } - s->irep->slen = 256; - } - s->irep->syms[s->irep->slen] = sym; - return s->irep->slen++; -} - -static int -node_len(node *tree) -{ - int n = 0; - - while (tree) { - n++; - tree = tree->cdr; - } - return n; -} - -#define sym(x) ((mrb_sym)(intptr_t)(x)) -#define lv_name(lv) sym((lv)->car) -static int -lv_idx(codegen_scope *s, mrb_sym id) -{ - node *lv = s->lv; - int n = 1; - - while (lv) { - if (lv_name(lv) == id) return n; - n++; - lv = lv->cdr; - } - return 0; -} - -static void -for_body(codegen_scope *s, node *tree) -{ - codegen_scope *prev = s; - int idx; - struct loopinfo *lp; - node *n2; - mrb_code c; - - /* generate receiver */ - codegen(s, tree->cdr->car, VAL); - /* generate loop-block */ - s = scope_new(s->mrb, s, NULL); - if (s == NULL) { - raise_error(prev, "unexpected scope"); - } - - push(); /* push for a block parameter */ - - lp = loop_push(s, LOOP_FOR); - lp->pc1 = new_label(s); - - /* generate loop variable */ - n2 = tree->car; - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); - if (n2->car && !n2->car->cdr && !n2->cdr) { - gen_assignment(s, n2->car->car, 1, NOVAL); - } - else { - gen_vmassignment(s, n2, 1, VAL); - } - codegen(s, tree->cdr->cdr->car, VAL); - pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - loop_pop(s, NOVAL); - scope_finish(s); - s = prev; - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); - pop(); - 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) -{ - mrb_code c; - codegen_scope *parent = s; - s = scope_new(s->mrb, s, tree->car); - if (s == NULL) { - raise_error(parent, "unexpected scope"); - } - - s->mscope = !blk; - - if (blk) { - struct loopinfo *lp = loop_push(s, LOOP_BLOCK); - lp->pc1 = new_label(s); - } - tree = tree->cdr; - if (tree->car) { - mrb_aspec a; - int ma, oa, ra, pa, ka, kd, ba; - int pos, i; - node *n, *opt; - - ma = node_len(tree->car->car); - n = tree->car->car; - while (n) { - n = n->cdr; - } - oa = node_len(tree->car->cdr->car); - ra = tree->car->cdr->cdr->car ? 1 : 0; - pa = node_len(tree->car->cdr->cdr->cdr->car); - ka = kd = 0; - ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; - - a = ((mrb_aspec)(ma & 0x1f) << 18) - | ((mrb_aspec)(oa & 0x1f) << 13) - | ((ra & 1) << 12) - | ((pa & 0x1f) << 7) - | ((ka & 0x1f) << 2) - | ((kd & 1)<< 1) - | (ba & 1); - s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ - | ((ra & 1) << 5) - | (pa & 0x1f); - genop(s, MKOP_Ax(OP_ENTER, a)); - pos = new_label(s); - for (i=0; i<oa; i++) { - new_label(s); - genop(s, MKOP_sBx(OP_JMP, 0)); - } - if (oa > 0) { - genop(s, MKOP_sBx(OP_JMP, 0)); - } - opt = tree->car->cdr->car; - i = 0; - while (opt) { - int idx; - - dispatch(s, pos+i); - codegen(s, opt->car->cdr, VAL); - idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car); - pop(); - genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); - i++; - opt = opt->cdr; - } - if (oa > 0) { - dispatch(s, pos+i); - } - } - codegen(s, tree->cdr->car, VAL); - pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { - if (s->nregs == 0) { - genop(s, MKOP_A(OP_LOADNIL, 0)); - genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - } - } - if (blk) { - loop_pop(s, NOVAL); - } - scope_finish(s); - return parent->irep->rlen - 1; -} - -static int -scope_body(codegen_scope *s, node *tree, int val) -{ - codegen_scope *scope = scope_new(s->mrb, s, tree->car); - if (scope == NULL) { - raise_error(s, "unexpected scope"); - } - - 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-1, OP_R_NORMAL), NOVAL); - } - } - scope_finish(scope); - if (!s->irep) { - /* should not happen */ - return 0; - } - return s->irep->rlen - 1; -} - -static mrb_bool -nosplat(node *t) -{ - while (t) { - if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE; - t = t->cdr; - } - return TRUE; -} - -static mrb_sym -attrsym(codegen_scope *s, mrb_sym a) -{ - const char *name; - mrb_int len; - char *name2; - - name = mrb_sym2name_len(s->mrb, a, &len); - name2 = (char *)codegen_palloc(s, - (size_t)len - + 1 /* '=' */ - + 1 /* '\0' */ - ); - mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); - memcpy(name2, name, (size_t)len); - name2[len] = '='; - name2[len+1] = '\0'; - - 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) { - 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(); - 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(); - codegen(s, t->car, VAL); - pop(); pop(); - if ((intptr_t)t->car->car == NODE_SPLAT) { - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); - } - else { - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - } - t = t->cdr; - } - } - else { - codegen(s, t->car->cdr, NOVAL); - t = t->cdr; - while (t) { - codegen(s, t->car, NOVAL); - t = t->cdr; - } - } - return -1; - } - /* normal (no splat) mode */ - codegen(s, t->car, val); - n++; - t = t->cdr; - } - return n; -} - -#define CALL_MAXARGS 127 - -static void -gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val) -{ - mrb_sym sym = name ? name : sym(tree->cdr->car); - int idx; - int n = 0, noop = 0, sendv = 0, blk = 0; - - codegen(s, tree->car, VAL); /* receiver */ - idx = new_msym(s, sym); - tree = tree->cdr->cdr->car; - if (tree) { - n = gen_values(s, tree->car, VAL); - if (n < 0) { - n = noop = sendv = 1; - push(); - } - } - if (sp) { - if (sendv) { - pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); - push(); - } - else { - genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); - push(); - n++; - } - } - if (tree && tree->cdr) { - noop = 1; - codegen(s, tree->cdr, VAL); - pop(); - } - else { - blk = cursp(); - } - push();pop(); - pop_n(n+1); - { - mrb_int symlen; - const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); - - if (!noop && symlen == 1 && symname[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); - } - else if (!noop && symlen == 1 && symname[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); - } - else if (!noop && symlen == 1 && symname[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); - } - else { - if (sendv) n = CALL_MAXARGS; - if (blk > 0) { /* no block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); - } - else { - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); - } - } - } - if (val) { - push(); - } -} - -static void -gen_assignment(codegen_scope *s, node *tree, int sp, int val) -{ - int idx; - int type = (intptr_t)tree->car; - - tree = tree->cdr; - switch ((intptr_t)type) { - case NODE_GVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); - break; - case NODE_LVAR: - idx = lv_idx(s, sym(tree)); - if (idx > 0) { - if (idx != sp) { - genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); - } - break; - } - else { /* upvar */ - int lv = 0; - codegen_scope *up = s->prev; - - while (up) { - idx = lv_idx(up, sym(tree)); - if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); - break; - } - lv++; - up = up->prev; - } - } - break; - case NODE_IVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); - break; - case NODE_CVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); - break; - case NODE_CONST: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); - break; - case NODE_COLON2: - idx = new_sym(s, sym(tree->cdr)); - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); - push(); - codegen(s, tree->car, VAL); - pop_n(2); - genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); - break; - - case NODE_CALL: - push(); - gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); - pop(); - if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); - } - break; - - case NODE_MASGN: - gen_vmassignment(s, tree->car, sp, val); - break; - - push(); - gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); - pop(); - if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); - } - break; - /* splat without assignment */ - case NODE_NIL: - break; - - default: -#ifdef ENABLE_STDIO - printf("unknown lhs %d\n", type); -#endif - break; - } - if (val) push(); -} - -static void -gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) -{ - int n = 0, post = 0; - node *t, *p; - - if (tree->car) { /* pre */ - t = tree->car; - n = 0; - while (t) { - genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n)); - gen_assignment(s, t->car, cursp(), NOVAL); - n++; - t = t->cdr; - } - } - t = tree->cdr; - if (t) { - if (t->cdr) { /* post count */ - p = t->cdr->car; - while (p) { - post++; - p = p->cdr; - } - } - if (val) { - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); - } - else { - pop(); - } - genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); - n = 1; - if (t->car) { /* rest */ - gen_assignment(s, t->car, cursp(), NOVAL); - } - if (t->cdr && t->cdr->car) { - t = t->cdr->car; - while (t) { - gen_assignment(s, t->car, cursp()+n, NOVAL); - t = t->cdr; - n++; - } - } - push(); - } -} - -static void -gen_send_intern(codegen_scope *s) -{ - pop(); - 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, mrb_bool sym, int val) -{ - if (val) { - int i = 0, j = 0; - - while (tree) { - switch ((intptr_t)tree->car->car) { - case NODE_STR: - if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0)) - break; - /* fall through */ - case NODE_BEGIN: - codegen(s, tree->car, VAL); - ++j; - break; - - case NODE_LITERAL_DELIM: - if (j > 0) { - j = 0; - ++i; - if (sym) - gen_send_intern(s); - } - break; - } - if (j >= 2) { - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - j = 1; - } - tree = tree->cdr; - } - if (j > 0) { - ++i; - if (sym) - gen_send_intern(s); - } - pop_n(i); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); - push(); - } - else { - while (tree) { - switch ((intptr_t)tree->car->car) { - case NODE_BEGIN: case NODE_BLOCK: - codegen(s, tree->car, NOVAL); - } - tree = tree->cdr; - } - } -} - -static void -raise_error(codegen_scope *s, const char *msg) -{ - int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); - - genop(s, MKOP_ABx(OP_ERR, 1, idx)); -} - -static double -readint_float(codegen_scope *s, const char *p, int base) -{ - const char *e = p + strlen(p); - double f = 0; - int n; - - if (*p == '+') p++; - while (p < e) { - char c = *p; - c = tolower((unsigned char)c); - for (n=0; n<base; n++) { - if (mrb_digitmap[n] == c) { - f *= base; - f += n; - break; - } - } - if (n == base) { - codegen_error(s, "malformed readint input"); - } - p++; - } - return f; -} - -static mrb_int -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; - int n; - - mrb_assert(base >= 2 && base <= 36); - if (*p == '+') p++; - while (p < e) { - char c = *p; - c = tolower((unsigned char)c); - for (n=0; n<base; n++) { - if (mrb_digitmap[n] == c) { - break; - } - } - if (n == base) { - codegen_error(s, "malformed readint input"); - } - - if (neg) { - if ((MRB_INT_MIN + n)/base > result) { - *overflow = TRUE; - return 0; - } - result *= base; - result -= n; - } - else { - if ((MRB_INT_MAX - n)/base < result) { - *overflow = TRUE; - return 0; - } - result *= base; - result += n; - } - p++; - } - *overflow = FALSE; - return result; -} - -static void -codegen(codegen_scope *s, node *tree, int val) -{ - int nt; - - if (!tree) return; - - if (s->irep && 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; - switch (nt) { - case NODE_BEGIN: - if (val && !tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - while (tree) { - codegen(s, tree->car, tree->cdr ? NOVAL : val); - tree = tree->cdr; - } - break; - - case NODE_RESCUE: - { - int onerr, noexc, exend, pos1, pos2, tmp; - struct loopinfo *lp; - - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); - lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; - if (tree->car) { - codegen(s, tree->car, val); - if (val) pop(); - } - lp->type = LOOP_RESCUE; - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); - dispatch(s, onerr); - tree = tree->cdr; - exend = 0; - pos1 = 0; - if (tree->car) { - node *n2 = tree->car; - int exc = cursp(); - - genop(s, MKOP_A(OP_RESCUE, exc)); - push(); - while (n2) { - node *n3 = n2->car; - node *n4 = n3->car; - - if (pos1) dispatch(s, pos1); - pos2 = 0; - do { - if (n4) { - codegen(s, n4->car, VAL); - } - else { - 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(); - 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 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch_linked(s, pos2); - - pop(); - if (n3->cdr->car) { - gen_assignment(s, n3->cdr->car, exc, NOVAL); - } - if (n3->cdr->cdr->car) { - codegen(s, n3->cdr->cdr->car, val); - if (val) pop(); - } - tmp = genop(s, MKOP_sBx(OP_JMP, exend)); - exend = tmp; - n2 = n2->cdr; - push(); - } - if (pos1) { - dispatch(s, pos1); - genop(s, MKOP_A(OP_RAISE, exc)); - } - } - pop(); - tree = tree->cdr; - dispatch(s, noexc); - genop(s, MKOP_A(OP_POPERR, 1)); - if (tree->car) { - codegen(s, tree->car, val); - } - else if (val) { - push(); - } - dispatch_linked(s, exend); - loop_pop(s, NOVAL); - } - break; - - case NODE_ENSURE: - { - int idx; - int epush = s->pc; - - genop(s, MKOP_Bx(OP_EPUSH, 0)); - s->ensure_level++; - codegen(s, tree->car, val); - 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); - } - break; - - case NODE_LAMBDA: - { - int idx = lambda_body(s, tree, 1); - - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); - push(); - } - break; - - case NODE_BLOCK: - { - int idx = lambda_body(s, tree, 1); - - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); - push(); - } - break; - - case NODE_IF: - { - int pos1, pos2; - node *e = tree->cdr->cdr->car; - - codegen(s, tree->car, VAL); - pop(); - pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); - - codegen(s, tree->cdr->car, val); - if (val && !(tree->cdr->car)) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - if (e) { - if (val) pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch(s, pos1); - codegen(s, e, val); - dispatch(s, pos2); - } - else { - if (val) { - pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch(s, pos1); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - dispatch(s, pos2); - push(); - } - else { - dispatch(s, pos1); - } - } - } - break; - - case NODE_AND: - { - int pos; - - codegen(s, tree->car, VAL); - pop(); - pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } - break; - - case NODE_OR: - { - int pos; - - codegen(s, tree->car, VAL); - pop(); - pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } - break; - - case NODE_WHILE: - { - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); - - loop_pop(s, val); - } - break; - - case NODE_UNTIL: - { - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); - - loop_pop(s, val); - } - break; - - case NODE_FOR: - for_body(s, tree); - if (val) push(); - break; - - case NODE_CASE: - { - int head = 0; - int pos1, pos2, pos3, tmp; - node *n; - - pos3 = 0; - if (tree->car) { - head = cursp(); - codegen(s, tree->car, VAL); - } - tree = tree->cdr; - while (tree) { - n = tree->car->car; - pos1 = pos2 = 0; - while (n) { - codegen(s, n->car, VAL); - if (head) { - genop(s, MKOP_AB(OP_MOVE, cursp(), head)); - pop(); - 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 = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); - pos2 = tmp; - n = n->cdr; - } - if (tree->car->car) { - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch_linked(s, pos2); - } - codegen(s, tree->car->cdr, val); - if (val) pop(); - 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); - if (head) pop(); - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); - push(); - } - else { - if (pos3) { - dispatch_linked(s, pos3); - } - if (head) { - pop(); - } - } - } - break; - - case NODE_SCOPE: - scope_body(s, tree, NOVAL); - break; - - case NODE_FCALL: - case NODE_CALL: - gen_call(s, tree, 0, 0, val); - break; - - case NODE_DOT2: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); - push(); - } - break; - - case NODE_DOT3: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); - push(); - } - break; - - case NODE_COLON2: - { - int sym = new_sym(s, sym(tree->cdr)); - - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - if (val) push(); - } - break; - - case NODE_COLON3: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - if (val) push(); - } - break; - - case NODE_ARRAY: - { - int n; - - n = gen_values(s, tree, val); - if (n >= 0) { - if (val) { - pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); - push(); - } - } - else if (val) { - push(); - } - } - break; - - 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(); - } - } - break; - - case NODE_SPLAT: - codegen(s, tree, VAL); - break; - - case NODE_ASGN: - codegen(s, tree->cdr, VAL); - pop(); - gen_assignment(s, tree->car, cursp(), val); - break; - - case NODE_MASGN: - { - int len = 0, n = 0, post = 0; - node *t = tree->cdr, *p; - int rhs = cursp(); - - if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) { - /* fixed rhs */ - t = t->cdr; - while (t) { - codegen(s, t->car, VAL); - len++; - t = t->cdr; - } - tree = tree->car; - if (tree->car) { /* pre */ - t = tree->car; - n = 0; - while (t) { - gen_assignment(s, t->car, rhs+n, NOVAL); - n++; - t = t->cdr; - } - } - t = tree->cdr; - if (t) { - if (t->cdr) { /* post count */ - p = t->cdr->car; - while (p) { - post++; - p = p->cdr; - } - } - if (t->car) { /* rest (len - pre - post) */ - int rn = len - post - n; - - genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); - gen_assignment(s, t->car, cursp(), NOVAL); - n += rn; - } - if (t->cdr && t->cdr->car) { - t = t->cdr->car; - while (n<len) { - gen_assignment(s, t->car, rhs+n, NOVAL); - t = t->cdr; - n++; - } - } - } - pop_n(len); - if (val) { - genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); - push(); - } - } - else { - /* variable rhs */ - codegen(s, t, VAL); - gen_vmassignment(s, tree->car, rhs, val); - if (!val) { - pop(); - } - } - } - break; - - case NODE_OP_ASGN: - { - mrb_sym sym = sym(tree->cdr->car); - mrb_int len; - const char *name = mrb_sym2name_len(s->mrb, sym, &len); - int idx; - - codegen(s, tree->car, VAL); - if (len == 2 && - ((name[0] == '|' && name[1] == '|') || - (name[0] == '&' && name[1] == '&'))) { - int pos; - - pop(); - 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); - dispatch(s, pos); - break; - } - codegen(s, tree->cdr->cdr->car, VAL); - push(); pop(); - pop(); pop(); - - idx = new_msym(s, sym); - if (len == 1 && name[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); - } - else if (len == 1 && name[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); - } - else if (len == 1 && name[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); - } - else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); - } - else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); - } - else { - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); - } - } - gen_assignment(s, tree->car, cursp(), val); - break; - - case NODE_SUPER: - { - int n = 0, noop = 0, sendv = 0; - - push(); /* room for receiver */ - if (tree) { - node *args = tree->car; - if (args) { - n = gen_values(s, args, VAL); - if (n < 0) { - n = noop = sendv = 1; - push(); - } - } - } - if (tree && tree->cdr) { - codegen(s, tree->cdr, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); pop(); - } - pop_n(n+1); - if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); - if (val) push(); - } - break; - - case NODE_ZSUPER: - { - codegen_scope *s2 = s; - int lv = 0, ainfo = 0; - - push(); /* room for receiver */ - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); - push(); push(); pop(); /* ARGARY pushes two values */ - if (tree && tree->cdr) { - codegen(s, tree->cdr, VAL); - pop(); - } - pop(); pop(); - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); - if (val) push(); - } - break; - - case NODE_RETURN: - if (tree) { - codegen(s, tree, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - if (s->loop) { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - if (val) push(); - break; - - case NODE_YIELD: - { - codegen_scope *s2 = s; - int lv = 0, ainfo = 0; - int n = 0, sendv = 0; - - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); - push(); - if (tree) { - n = gen_values(s, tree, VAL); - if (n < 0) { - n = sendv = 1; - push(); - } - } - pop_n(n+1); - if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); - if (val) push(); - } - break; - - case NODE_BREAK: - loop_break(s, tree); - if (val) push(); - break; - - case NODE_NEXT: - if (!s->loop) { - raise_error(s, "unexpected next"); - } - else if (s->loop->type == LOOP_NORMAL) { - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - codegen(s, tree, NOVAL); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); - } - else { - if (tree) { - codegen(s, tree, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - if (val) push(); - break; - - case NODE_REDO: - if (!s->loop) { - raise_error(s, "unexpected redo"); - } - else { - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); - } - break; - - case NODE_RETRY: - { - const char *msg = "unexpected retry"; - - if (!s->loop) { - raise_error(s, msg); - } - else { - struct loopinfo *lp = s->loop; - int n = 0; - - while (lp && lp->type != LOOP_RESCUE) { - if (lp->type == LOOP_BEGIN) { - n++; - } - lp = lp->prev; - } - if (!lp) { - raise_error(s, msg); - } - else { - if (n > 0) { - while (n--) { - genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); - } - } - if (s->ensure_level > lp->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); - } - genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); - } - } - } - break; - - case NODE_LVAR: - if (val) { - int idx = lv_idx(s, sym(tree)); - - if (idx > 0) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); - } - else { - int lv = 0; - codegen_scope *up = s->prev; - - while (up) { - idx = lv_idx(up, sym(tree)); - if (idx > 0) { - genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv)); - break; - } - lv++; - up = up->prev; - } - } - push(); - } - break; - - case NODE_GVAR: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); - } - break; - - case NODE_IVAR: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); - push(); - } - break; - - case NODE_CVAR: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); - push(); - } - break; - - case NODE_CONST: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - push(); - } - break; - - case NODE_DEFINED: - codegen(s, tree, VAL); - break; - - case NODE_BACK_REF: - { - char buf[2] = { '$' }; - mrb_value str; - int sym; - - buf[1] = (char)(intptr_t)tree; - str = mrb_str_new(s->mrb, buf, 2); - sym = new_sym(s, mrb_intern_str(s->mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); - } - break; - - case NODE_NTH_REF: - { - int sym; - mrb_state *mrb = s->mrb; - mrb_value fix = mrb_fixnum_value((intptr_t)tree); - mrb_value str = mrb_str_buf_new(mrb, 4); - - mrb_str_cat_lit(mrb, str, "$"); - mrb_str_cat_str(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)); - push(); - } - break; - - case NODE_ARG: - /* should not happen */ - break; - - case NODE_BLOCK_ARG: - codegen(s, tree, VAL); - break; - - case NODE_INT: - if (val) { - char *p = (char*)tree->car; - int base = (intptr_t)tree->cdr->car; - mrb_int i; - mrb_code co; - mrb_bool overflow; - - i = readint_mrb_int(s, p, base, FALSE, &overflow); - if (overflow) { - double f = readint_float(s, p, base); - int off = new_lit(s, mrb_float_value(s->mrb, f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - } - else { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } - else { - int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); - } - genop(s, co); - } - push(); - } - break; - - case NODE_FLOAT: - if (val) { - char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); - int off = new_lit(s, mrb_float_value(s->mrb, f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - push(); - } - break; - - case NODE_NEGATE: - { - nt = (intptr_t)tree->car; - tree = tree->cdr; - switch (nt) { - case NODE_FLOAT: - { - char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); - int off = new_lit(s, mrb_float_value(s->mrb, -f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - push(); - } - break; - - case NODE_INT: - { - char *p = (char*)tree->car; - int base = (intptr_t)tree->cdr->car; - mrb_int i; - mrb_code co; - mrb_bool overflow; - - i = readint_mrb_int(s, p, base, TRUE, &overflow); - if (overflow) { - double f = readint_float(s, p, base); - int off = new_lit(s, mrb_float_value(s->mrb, -f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - } - else { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } - else { - int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); - } - genop(s, co); - } - push(); - } - break; - - default: - { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); - - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); - push(); - codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); - } - break; - } - } - break; - - case NODE_STR: - if (val) { - char *p = (char*)tree->car; - size_t len = (intptr_t)tree->cdr; - int ai = mrb_gc_arena_save(s->mrb); - int off = new_lit(s, mrb_str_new(s->mrb, p, len)); - - mrb_gc_arena_restore(s->mrb, ai); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - push(); - } - break; - - case NODE_HEREDOC: - tree = ((struct mrb_parser_heredoc_info *)tree)->doc; - /* fall through */ - case NODE_DSTR: - if (val) { - node *n = tree; - - if (!n) break; - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - n = n->cdr; - } - } - else { - node *n = tree; - - while (n) { - if ((intptr_t)n->car->car != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } - break; - - case NODE_WORDS: - gen_literal_array(s, tree, FALSE, val); - break; - - case NODE_SYMBOLS: - 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: - { - 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_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_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_REGX: - if (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_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())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - if (p2) { - push(); - 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_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); - mrb_gc_arena_restore(s->mrb, ai); - push(); - } - break; - - case NODE_DREGX: - if (val) { - node *n = tree->car; - int ai = mrb_gc_arena_save(s->mrb); - int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); - int argc = 1; - int off; - char *p; - - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - n = n->cdr; - } - n = tree->cdr->cdr; - if (n->car) { - p = (char*)n->car; - 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(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - } - if (n->cdr) { - char *p2 = (char*)n->cdr; - - push(); - 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_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); - mrb_gc_arena_restore(s->mrb, ai); - push(); - } - else { - node *n = tree->car; - - while (n) { - if ((intptr_t)n->car->car != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } - break; - - case NODE_SYM: - if (val) { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - break; - - case NODE_DSYM: - codegen(s, tree, val); - if (val) { - gen_send_intern(s); - } - break; - - case NODE_SELF: - if (val) { - genop(s, MKOP_A(OP_LOADSELF, cursp())); - push(); - } - break; - - case NODE_NIL: - if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - break; - - case NODE_TRUE: - if (val) { - genop(s, MKOP_A(OP_LOADT, cursp())); - push(); - } - break; - - case NODE_FALSE: - if (val) { - genop(s, MKOP_A(OP_LOADF, cursp())); - push(); - } - break; - - case NODE_ALIAS: - { - int a = new_msym(s, sym(tree->car)); - int b = new_msym(s, sym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); - push(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - pop_n(3); - genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); - if (val) { - push(); - } - } - break; - - case NODE_UNDEF: - { - int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); - int num = 0; - node *t = tree; - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - while (t) { - int symbol = new_msym(s, sym(t->car)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - push(); - t = t->cdr; - num++; - } - pop_n(num + 1); - genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); - if (val) { - push(); - } - } - break; - - case NODE_CLASS: - { - int idx; - - if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); - push(); - } - else { - codegen(s, tree->car->car, VAL); - } - if (tree->cdr->car) { - codegen(s, tree->cdr->car, VAL); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - 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, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_MODULE: - { - int idx; - - if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); - push(); - } - else { - codegen(s, tree->car->car, 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, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_SCLASS: - { - int idx; - - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_DEF: - { - int sym = new_msym(s, sym(tree->car)); - int idx = lambda_body(s, tree->cdr, 0); - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); - push(); pop(); - pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); - if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - } - break; - - case NODE_SDEF: - { - node *recv = tree->car; - int sym = new_msym(s, sym(tree->cdr->car)); - int idx = lambda_body(s, tree->cdr->cdr, 0); - - codegen(s, recv, VAL); - pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); - pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); - if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - } - break; - - case NODE_POSTEXE: - codegen(s, tree, NOVAL); - break; - - default: - break; - } -} - -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) -{ - static const codegen_scope codegen_scope_zero = { 0 }; - mrb_pool *pool = mrb_pool_open(mrb); - codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); - - if (!p) return NULL; - *p = codegen_scope_zero; - p->mrb = mrb; - p->mpool = pool; - if (!prev) return p; - p->prev = prev; - p->ainfo = -1; - p->mscope = 0; - - p->irep = mrb_add_irep(mrb); - 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)*p->scapa); - p->irep->slen = 0; - - p->lv = lv; - p->sp += node_len(lv)+1; /* add self */ - p->nlocals = p->sp; - if (lv) { - node *n = lv; - size_t i = 0; - - p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1)); - for (i=0, n=lv; n; i++,n=n->cdr) { - p->irep->lv[i].name = lv_name(n); - if (lv_name(n)) { - p->irep->lv[i].r = lv_idx(p, lv_name(n)); - } - else { - p->irep->lv[i].r = 0; - } - } - mrb_assert(i + 1 == p->nlocals); - } - p->ai = mrb_gc_arena_save(mrb); - - p->filename = prev->filename; - if (p->filename) { - 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; -} - -static void -scope_finish(codegen_scope *s) -{ - mrb_state *mrb = s->mrb; - mrb_irep *irep = s->irep; - size_t fname_len; - char *fname; - - irep->flags = 0; - if (s->iseq) { - irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); - irep->ilen = s->pc; - if (s->lines) { - irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); - } - else { - 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->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 = (char*)codegen_malloc(s, fname_len + 1); - memcpy(fname, s->filename, fname_len); - fname[fname_len] = '\0'; - irep->filename = fname; - } - - irep->nlocals = s->nlocals; - irep->nregs = s->nregs; - - mrb_gc_arena_restore(mrb, s->ai); - mrb_pool_close(s->mpool); -} - -static struct loopinfo* -loop_push(codegen_scope *s, enum looptype t) -{ - struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); - - p->type = t; - p->pc1 = p->pc2 = p->pc3 = 0; - p->prev = s->loop; - p->ensure_level = s->ensure_level; - p->acc = cursp(); - s->loop = p; - - return p; -} - -static void -loop_break(codegen_scope *s, node *tree) -{ - if (!s->loop) { - codegen(s, tree, NOVAL); - raise_error(s, "unexpected break"); - } - else { - struct loopinfo *loop; - - if (tree) { - codegen(s, tree, VAL); - pop(); - } - - loop = s->loop; - while (loop->type == LOOP_BEGIN) { - genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); - loop = loop->prev; - } - while (loop->type == LOOP_RESCUE) { - loop = loop->prev; - } - if (loop->type == LOOP_NORMAL) { - int tmp; - - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - if (tree) { - genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); - } - tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); - loop->pc3 = tmp; - } - else { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); - } - } -} - -static void -loop_pop(codegen_scope *s, int val) -{ - if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - dispatch_linked(s, s->loop->pc3); - s->loop = s->loop->prev; - if (val) push(); -} - -MRB_API 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 NULL; - } - scope->mrb = mrb; - 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 proc; - } - 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; - } - MRB_END_EXC(&scope->jmp); -} diff --git a/src/dump.c b/src/dump.c index d9410ec18..734f38043 100644 --- a/src/dump.c +++ b/src/dump.c @@ -16,7 +16,7 @@ #define FLAG_BYTEORDER_NONATIVE 0 #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.9e" +#define MRB_FLOAT_FMT "%.8e" #else #define MRB_FLOAT_FMT "%.16e" #endif @@ -819,7 +819,6 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 uint32_t offset; switch (flags & DUMP_ENDIAN_NAT) { - default: endian_big: case DUMP_ENDIAN_BIG: memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); @@ -979,12 +978,8 @@ error_exit: mrb_free(mrb, *bin); *bin = NULL; } - if (lv_syms) { - mrb_free(mrb, lv_syms); - } - if (filenames) { - mrb_free(mrb, filenames); - } + mrb_free(mrb, lv_syms); + mrb_free(mrb, filenames); return result; } diff --git a/src/error.c b/src/error.c index a800f77f9..359e5737b 100644 --- a/src/error.c +++ b/src/error.c @@ -152,7 +152,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) mrb_str_append(mrb, str, line); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); mrb_str_cat_lit(mrb, str, " ("); } mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); @@ -165,7 +165,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) str = mrb_str_new_cstr(mrb, cname); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); } else { mrb_str_cat_cstr(mrb, str, cname); @@ -424,15 +424,14 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) } MRB_API mrb_noreturn void -mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...) +mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...) { mrb_value exc; va_list ap; va_start(ap, fmt); exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3, - mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), - mrb_ary_new_from_values(mrb, argc, argv)); + mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), args); va_end(ap); mrb_exc_raise(mrb, exc); } @@ -26,7 +26,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_immediate_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { mrb_check_type(mrb, obj, MRB_TT_DATA); } if (DATA_TYPE(obj) != type) { @@ -48,7 +48,7 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API void* mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_immediate_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { return NULL; } if (DATA_TYPE(obj) != type) { @@ -67,17 +67,15 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_value tmp; mrb_sym id; switch (mrb_type(name)) { default: - tmp = mrb_check_string_type(mrb, name); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); + name = mrb_check_string_type(mrb, name); + if (mrb_nil_p(name)) { + name = mrb_inspect(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); } - name = tmp; /* fall through */ case MRB_TT_STRING: name = mrb_str_intern(mrb, name); diff --git a/src/fmt_fp.c b/src/fmt_fp.c index ef2f19dd5..b27ebd6e9 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -90,12 +90,9 @@ fmt_u(uint32_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -#if defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips) -static long double -frexpl (long double x, int *eptr) -{ - return frexp(x, eptr); -} +#if ((defined(__CYGWIN__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) +#undef frexpl +#define frexpl frexp #endif static int @@ -498,7 +498,12 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) mrb_gc_mark(mrb, (struct RBasic*)obj->c); switch (obj->tt) { case MRB_TT_ICLASS: - mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); + { + struct RClass *c = (struct RClass*)obj; + if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN)) + mrb_gc_mark_mt(mrb, c); + mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); + } break; case MRB_TT_CLASS: @@ -624,7 +629,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj) mrb_gc_free_mt(mrb, (struct RClass*)obj); mrb_gc_free_iv(mrb, (struct RObject*)obj); break; - + case MRB_TT_ICLASS: + if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + mrb_gc_free_mt(mrb, (struct RClass*)obj); + break; case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; diff --git a/src/hash.c b/src/hash.c index 0bda2b48b..ffb8bd931 100644 --- a/src/hash.c +++ b/src/hash.c @@ -104,10 +104,11 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key)) - return mrb_str_dup(mrb, key); - else - return key; + if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) { + key = mrb_str_dup(mrb, key); + RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); + } + return key; } #define KEY(key) mrb_hash_ht_key(mrb, key) diff --git a/src/kernel.c b/src/kernel.c index d1e10a7f8..225f7fa54 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -240,14 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) /* copy singleton(unnamed) class */ struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class); - if ((mrb_type(obj) == MRB_TT_CLASS) || - (mrb_type(obj) == MRB_TT_SCLASS)) { /* BUILTIN_TYPE(obj) == T_CLASS */ + if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) { clone->c = clone; } else { clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); } - clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -269,6 +267,21 @@ 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); + /* if the origin is not the same as the class, then the origin and + the current class need to be copied */ + if (sc->flags & MRB_FLAG_IS_PREPENDED) { + struct RClass *c0 = sc->super; + struct RClass *c1 = dc; + + /* copy prepended iclasses */ + while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1 = c1->super; + c0 = c0->super; + } + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1->super->flags |= MRB_FLAG_IS_ORIGIN; + } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; } @@ -330,6 +343,9 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) if (mrb_immediate_p(self)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } + if (mrb_type(self) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); + } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); clone = mrb_obj_value(p); @@ -366,6 +382,9 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) if (mrb_immediate_p(obj)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); } + if (mrb_type(obj) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); + } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); dup = mrb_obj_value(p); init_copy(mrb, dup, obj); @@ -635,13 +654,19 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl { khint_t i; mrb_value ary; + mrb_bool prepended; struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); + if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + prepended = 1; + } + oldklass = 0; while (klass && (klass != oldklass)) { method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS) || + if ((klass->tt == MRB_TT_ICLASS && !prepended) || (klass->tt == MRB_TT_SCLASS)) { } else { diff --git a/src/keywords b/src/keywords deleted file mode 100644 index 9cb86608c..000000000 --- a/src/keywords +++ /dev/null @@ -1,50 +0,0 @@ -%{ -struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) -%} - -struct kwtable; -%% -__ENCODING__, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END -__FILE__, {keyword__FILE__, keyword__FILE__}, EXPR_END -__LINE__, {keyword__LINE__, keyword__LINE__}, EXPR_END -BEGIN, {keyword_BEGIN, keyword_BEGIN}, EXPR_END -END, {keyword_END, keyword_END}, EXPR_END -alias, {keyword_alias, keyword_alias}, EXPR_FNAME -and, {keyword_and, keyword_and}, EXPR_VALUE -begin, {keyword_begin, keyword_begin}, EXPR_BEG -break, {keyword_break, keyword_break}, EXPR_MID -case, {keyword_case, keyword_case}, EXPR_VALUE -class, {keyword_class, keyword_class}, EXPR_CLASS -def, {keyword_def, keyword_def}, EXPR_FNAME -do, {keyword_do, keyword_do}, EXPR_BEG -else, {keyword_else, keyword_else}, EXPR_BEG -elsif, {keyword_elsif, keyword_elsif}, EXPR_VALUE -end, {keyword_end, keyword_end}, EXPR_END -ensure, {keyword_ensure, keyword_ensure}, EXPR_BEG -false, {keyword_false, keyword_false}, EXPR_END -for, {keyword_for, keyword_for}, EXPR_VALUE -if, {keyword_if, modifier_if}, EXPR_VALUE -in, {keyword_in, keyword_in}, EXPR_VALUE -module, {keyword_module, keyword_module}, EXPR_VALUE -next, {keyword_next, keyword_next}, EXPR_MID -nil, {keyword_nil, keyword_nil}, EXPR_END -not, {keyword_not, keyword_not}, EXPR_ARG -or, {keyword_or, keyword_or}, EXPR_VALUE -redo, {keyword_redo, keyword_redo}, EXPR_END -rescue, {keyword_rescue, modifier_rescue}, EXPR_MID -retry, {keyword_retry, keyword_retry}, EXPR_END -return, {keyword_return, keyword_return}, EXPR_MID -self, {keyword_self, keyword_self}, EXPR_END -super, {keyword_super, keyword_super}, EXPR_ARG -then, {keyword_then, keyword_then}, EXPR_BEG -true, {keyword_true, keyword_true}, EXPR_END -undef, {keyword_undef, keyword_undef}, EXPR_FNAME -unless, {keyword_unless, modifier_unless}, EXPR_VALUE -until, {keyword_until, modifier_until}, EXPR_VALUE -when, {keyword_when, keyword_when}, EXPR_VALUE -while, {keyword_while, modifier_while}, EXPR_VALUE -yield, {keyword_yield, keyword_yield}, EXPR_ARG -%% diff --git a/src/lex.def b/src/lex.def deleted file mode 100644 index ea456a843..000000000 --- a/src/lex.def +++ /dev/null @@ -1,212 +0,0 @@ -/* ANSI-C code produced by gperf version 3.0.3 */ -/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to <[email protected]>." -#endif - -#line 1 "src/keywords" - -struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) -#line 8 "src/keywords" -struct kwtable; - -#define TOTAL_KEYWORDS 40 -#define MIN_WORD_LENGTH 2 -#define MAX_WORD_LENGTH 12 -#define MIN_HASH_VALUE 8 -#define MAX_HASH_VALUE 50 -/* maximum key range = 43, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (register const char *str, register unsigned int len) -{ - static const unsigned char asso_values[] = - { - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 14, 51, 16, 8, - 11, 13, 51, 51, 51, 51, 10, 51, 13, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 11, 51, 13, 1, 26, - 4, 1, 8, 28, 51, 23, 51, 1, 1, 27, - 5, 19, 21, 51, 8, 3, 3, 11, 51, 21, - 24, 16, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51 - }; - register int hval = len; - - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[2]]; - /*FALLTHROUGH*/ - case 2: - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval + asso_values[(unsigned char)str[len - 1]]; -} - -#ifdef __GNUC__ -__inline -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const struct kwtable * -mrb_reserved_word (register const char *str, register unsigned int len) -{ - static const struct kwtable wordlist[] = - { - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 18 "src/keywords" - {"break", {keyword_break, keyword_break}, EXPR_MID}, -#line 23 "src/keywords" - {"else", {keyword_else, keyword_else}, EXPR_BEG}, -#line 33 "src/keywords" - {"nil", {keyword_nil, keyword_nil}, EXPR_END}, -#line 26 "src/keywords" - {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, -#line 25 "src/keywords" - {"end", {keyword_end, keyword_end}, EXPR_END}, -#line 42 "src/keywords" - {"then", {keyword_then, keyword_then}, EXPR_BEG}, -#line 34 "src/keywords" - {"not", {keyword_not, keyword_not}, EXPR_ARG}, -#line 27 "src/keywords" - {"false", {keyword_false, keyword_false}, EXPR_END}, -#line 40 "src/keywords" - {"self", {keyword_self, keyword_self}, EXPR_END}, -#line 24 "src/keywords" - {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, -#line 37 "src/keywords" - {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, -#line 43 "src/keywords" - {"true", {keyword_true, keyword_true}, EXPR_END}, -#line 46 "src/keywords" - {"until", {keyword_until, modifier_until}, EXPR_VALUE}, -#line 45 "src/keywords" - {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, -#line 39 "src/keywords" - {"return", {keyword_return, keyword_return}, EXPR_MID}, -#line 21 "src/keywords" - {"def", {keyword_def, keyword_def}, EXPR_FNAME}, -#line 16 "src/keywords" - {"and", {keyword_and, keyword_and}, EXPR_VALUE}, -#line 22 "src/keywords" - {"do", {keyword_do, keyword_do}, EXPR_BEG}, -#line 49 "src/keywords" - {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, -#line 28 "src/keywords" - {"for", {keyword_for, keyword_for}, EXPR_VALUE}, -#line 44 "src/keywords" - {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, -#line 35 "src/keywords" - {"or", {keyword_or, keyword_or}, EXPR_VALUE}, -#line 30 "src/keywords" - {"in", {keyword_in, keyword_in}, EXPR_VALUE}, -#line 47 "src/keywords" - {"when", {keyword_when, keyword_when}, EXPR_VALUE}, -#line 38 "src/keywords" - {"retry", {keyword_retry, keyword_retry}, EXPR_END}, -#line 29 "src/keywords" - {"if", {keyword_if, modifier_if}, EXPR_VALUE}, -#line 19 "src/keywords" - {"case", {keyword_case, keyword_case}, EXPR_VALUE}, -#line 36 "src/keywords" - {"redo", {keyword_redo, keyword_redo}, EXPR_END}, -#line 32 "src/keywords" - {"next", {keyword_next, keyword_next}, EXPR_MID}, -#line 41 "src/keywords" - {"super", {keyword_super, keyword_super}, EXPR_ARG}, -#line 31 "src/keywords" - {"module", {keyword_module, keyword_module}, EXPR_VALUE}, -#line 17 "src/keywords" - {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, -#line 12 "src/keywords" - {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, -#line 11 "src/keywords" - {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, -#line 10 "src/keywords" - {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, -#line 14 "src/keywords" - {"END", {keyword_END, keyword_END}, EXPR_END}, -#line 15 "src/keywords" - {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, -#line 13 "src/keywords" - {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, - {""}, -#line 20 "src/keywords" - {"class", {keyword_class, keyword_class}, EXPR_CLASS}, - {""}, {""}, -#line 48 "src/keywords" - {"while", {keyword_while, modifier_while}, EXPR_VALUE} - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register const char *s = wordlist[key].name; - - if (*str == *s && !strcmp (str + 1, s + 1)) - return &wordlist[key]; - } - } - return 0; -} -#line 50 "src/keywords" - diff --git a/src/load.c b/src/load.c index a9f1641bf..36fae9aee 100644 --- a/src/load.c +++ b/src/load.c @@ -529,7 +529,7 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_LIL; - else + else *flags |= FLAG_BYTEORDER_NATIVE; } else { diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 88fca83fc..abde441d5 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -3,76 +3,17 @@ MRuby.each_target do relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" - lex_def = "#{current_dir}/lex.def" objs = Dir.glob("#{current_dir}/*.c").map { |f| - next nil if cxx_abi_enabled? and f =~ /(codegen|error|vm).c$/ + next nil if cxx_abi_enabled? and f =~ /(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", __FILE__] 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", __FILE__] 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 + objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end self.libmruby << objs file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| archiver.run t.name, t.prerequisites end - - # Parser - file "#{current_build_dir}/y.tab.c" => ["#{current_dir}/parse.y"] do |t| - yacc.run t.name, t.prerequisites.first - end - - # Lexical analyzer - file lex_def => "#{current_dir}/keywords" do |t| - gperf.run t.name, t.prerequisites.first - end end diff --git a/src/node.h b/src/node.h deleted file mode 100644 index 532a8323a..000000000 --- a/src/node.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -** node.h - nodes of abstract syntax tree -** -** See Copyright Notice in mruby.h -*/ - -#ifndef NODE_H -#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 -}; - -#endif /* NODE_H */ diff --git a/src/numeric.c b/src/numeric.c index 8b6ec4c88..1a3c903f0 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -55,7 +55,8 @@ num_pow(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); yv = mrb_to_flo(mrb, y); d = pow(mrb_to_flo(mrb, x), yv); - if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0) + if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0 && + (d < 0 || (d > 0 && (mrb_int)d > 0))) return mrb_fixnum_value((mrb_int)d); return mrb_float_value(mrb, d); } @@ -110,8 +111,8 @@ num_div(mrb_state *mrb, mrb_value x) * * Returns a string containing a representation of self. As well as a * fixed or exponential form of the number, the call may return - * ``<code>NaN</code>'', ``<code>Infinity</code>'', and - * ``<code>-Infinity</code>''. + * "<code>NaN</code>", "<code>Infinity</code>", and + * "<code>-Infinity</code>". */ static mrb_value @@ -436,7 +437,7 @@ flo_round(mrb_state *mrb, mrb_value num) { double number, f; mrb_int ndigits = 0; - int i; + mrb_int i; mrb_get_args(mrb, "|i", &ndigits); number = mrb_float(num); @@ -451,7 +452,7 @@ flo_round(mrb_state *mrb, mrb_value num) } f = 1.0; - i = abs(ndigits); + i = ndigits >= 0 ? ndigits : -ndigits; while (--i >= 0) f = f*10.0; @@ -819,11 +820,13 @@ fix_xor(mrb_state *mrb, mrb_value x) static mrb_value lshift(mrb_state *mrb, mrb_int val, mrb_int width) { - mrb_assert(width >= 0); + mrb_assert(width > 0); if (width > NUMERIC_SHIFT_WIDTH_MAX) { - mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)", - mrb_fixnum_value(width), - mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX)); + mrb_float f = (mrb_float)val; + while (width--) { + f *= 2; + } + return mrb_float_value(mrb, f); } return mrb_fixnum_value(val << width); } @@ -831,7 +834,7 @@ lshift(mrb_state *mrb, mrb_int val, mrb_int width) static mrb_value rshift(mrb_int val, mrb_int width) { - mrb_assert(width >= 0); + mrb_assert(width > 0); if (width >= NUMERIC_SHIFT_WIDTH_MAX) { if (val < 0) { return mrb_fixnum_value(-1); diff --git a/src/object.c b/src/object.c index c5fb74575..2e0bd245f 100644 --- a/src/object.c +++ b/src/object.c @@ -428,7 +428,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) * Returns a string representing <i>obj</i>. The default * <code>to_s</code> prints the object's class and an encoding of the * object id. As a special case, the top-level object that is the - * initial execution context of Ruby programs returns ``main.'' + * initial execution context of Ruby programs returns "main." */ MRB_API mrb_value @@ -487,6 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); } + MRB_CLASS_ORIGIN(c); while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; diff --git a/src/parse.y b/src/parse.y deleted file mode 100644 index 5b17649a9..000000000 --- a/src/parse.y +++ /dev/null @@ -1,6420 +0,0 @@ -/* -** parse.y - mruby parser -** -** See Copyright Notice in mruby.h -*/ - -%{ -#undef PARSER_DEBUG -#ifdef PARSER_DEBUG -# define YYDEBUG 1 -#endif -#define YYERROR_VERBOSE 1 -/* - * Force yacc to use our memory management. This is a little evil because - * the macros assume that "parser_state *p" is in scope - */ -#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) -#define YYFREE(o) mrb_free(p->mrb, (o)) -#define YYSTACK_USE_ALLOCA 0 - -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/proc.h" -#include "mruby/error.h" -#include "node.h" -#include "mruby/throw.h" - -#define YYLEX_PARAM p - -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); - -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - -typedef unsigned int stack_type; - -#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1)) -#define BITSTACK_POP(stack) ((stack) = (stack) >> 1) -#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1)) -#define BITSTACK_SET_P(stack) ((stack)&1) - -#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n)) -#define COND_POP() BITSTACK_POP(p->cond_stack) -#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack) -#define COND_P() BITSTACK_SET_P(p->cond_stack) - -#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n)) -#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack) -#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 NODE_LINENO(c,n) do {\ - if (n) {\ - (c)->filename_index = (n)->filename_index;\ - (c)->lineno = (n)->lineno;\ - }\ -} while (0) - -#define sym(x) ((mrb_sym)(intptr_t)(x)) -#define nsym(x) ((node*)(intptr_t)(x)) - -static inline mrb_sym -intern_cstr_gen(parser_state *p, const char *s) -{ - return mrb_intern_cstr(p->mrb, s); -} -#define intern_cstr(s) intern_cstr_gen(p,(s)) - -static inline mrb_sym -intern_gen(parser_state *p, const char *s, size_t len) -{ - return mrb_intern(p->mrb, 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_intern(p->mrb, &c, 1); -} -#define intern_c(c) intern_gen_c(p,(c)) - -static void -cons_free_gen(parser_state *p, node *cons) -{ - cons->cdr = p->cells; - p->cells = cons; -} -#define cons_free(c) cons_free_gen(p, (c)) - -static void* -parser_palloc(parser_state *p, size_t size) -{ - void *m = mrb_pool_alloc(p->pool, size); - - if (!m) { - MRB_THROW(p->jmp); - } - return m; -} - -static node* -cons_gen(parser_state *p, node *car, node *cdr) -{ - node *c; - - if (p->cells) { - c = p->cells; - p->cells = p->cells->cdr; - } - else { - c = (node *)parser_palloc(p, sizeof(mrb_ast_node)); - } - - 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)) - -static node* -list1_gen(parser_state *p, node *a) -{ - return cons(a, 0); -} -#define list1(a) list1_gen(p, (a)) - -static node* -list2_gen(parser_state *p, node *a, node *b) -{ - return cons(a, cons(b,0)); -} -#define list2(a,b) list2_gen(p, (a),(b)) - -static node* -list3_gen(parser_state *p, node *a, node *b, node *c) -{ - return cons(a, cons(b, cons(c,0))); -} -#define list3(a,b,c) list3_gen(p, (a),(b),(c)) - -static node* -list4_gen(parser_state *p, node *a, node *b, node *c, node *d) -{ - return cons(a, cons(b, cons(c, cons(d, 0)))); -} -#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d)) - -static node* -list5_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e) -{ - return cons(a, cons(b, cons(c, cons(d, cons(e, 0))))); -} -#define list5(a,b,c,d,e) list5_gen(p, (a),(b),(c),(d),(e)) - -static node* -list6_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e, node *f) -{ - return cons(a, cons(b, cons(c, cons(d, cons(e, cons(f, 0)))))); -} -#define list6(a,b,c,d,e,f) list6_gen(p, (a),(b),(c),(d),(e),(f)) - -static node* -append_gen(parser_state *p, node *a, node *b) -{ - node *c = a; - - if (!a) return b; - while (c->cdr) { - c = c->cdr; - } - if (b) { - c->cdr = b; - } - return a; -} -#define append(a,b) append_gen(p,(a),(b)) -#define push(a,b) append_gen(p,(a),list1(b)) - -static char* -parser_strndup(parser_state *p, const char *s, size_t len) -{ - char *b = (char *)parser_palloc(p, len+1); - - memcpy(b, s, len); - b[len] = '\0'; - return b; -} -#undef strndup -#define strndup(s,len) parser_strndup(p, s, len) - -static char* -parser_strdup(parser_state *p, const char *s) -{ - return parser_strndup(p, s, strlen(s)); -} -#undef strdup -#define strdup(s) parser_strdup(p, s) - -/* xxx ----------------------------- */ - -static node* -local_switch(parser_state *p) -{ - node *prev = p->locals; - - p->locals = cons(0, 0); - return prev; -} - -static void -local_resume(parser_state *p, node *prev) -{ - p->locals = prev; -} - -static void -local_nest(parser_state *p) -{ - p->locals = cons(0, p->locals); -} - -static void -local_unnest(parser_state *p) -{ - if (p->locals) { - p->locals = p->locals->cdr; - } -} - -static mrb_bool -local_var_p(parser_state *p, mrb_sym sym) -{ - node *l = p->locals; - - while (l) { - node *n = l->car; - while (n) { - if (sym(n->car) == sym) return TRUE; - n = n->cdr; - } - l = l->cdr; - } - return FALSE; -} - -static void -local_add_f(parser_state *p, mrb_sym sym) -{ - if (p->locals) { - p->locals->car = push(p->locals->car, nsym(sym)); - } -} - -static void -local_add(parser_state *p, mrb_sym sym) -{ - if (!local_var_p(p, sym)) { - local_add_f(p, sym); - } -} - -static node* -locals_node(parser_state *p) -{ - return p->locals ? p->locals->car : NULL; -} - -/* (:scope (vars..) (prog...)) */ -static node* -new_scope(parser_state *p, node *body) -{ - return cons((node*)NODE_SCOPE, cons(locals_node(p), body)); -} - -/* (:begin prog...) */ -static node* -new_begin(parser_state *p, node *body) -{ - if (body) { - return list2((node*)NODE_BEGIN, body); - } - return cons((node*)NODE_BEGIN, 0); -} - -#define newline_node(n) (n) - -/* (: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) */ -static node* -new_ensure(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_ENSURE, cons(a, cons(0, b))); -} - -/* (:nil) */ -static node* -new_nil(parser_state *p) -{ - return list1((node*)NODE_NIL); -} - -/* (:true) */ -static node* -new_true(parser_state *p) -{ - return list1((node*)NODE_TRUE); -} - -/* (:false) */ -static node* -new_false(parser_state *p) -{ - return list1((node*)NODE_FALSE); -} - -/* (: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) */ -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) */ -static node* -new_unless(parser_state *p, node *a, node *b, node *c) -{ - return list4((node*)NODE_IF, a, c, b); -} - -/* (: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) */ -static node* -new_until(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_UNTIL, cons(a, b)); -} - -/* (: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)) */ -static node* -new_case(parser_state *p, node *a, node *b) -{ - node *n = list2((node*)NODE_CASE, a); - node *n2 = n; - - while (n2->cdr) { - n2 = n2->cdr; - } - n2->cdr = b; - return n; -} - -/* (:postexe a) */ -static node* -new_postexe(parser_state *p, node *a) -{ - return cons((node*)NODE_POSTEXE, a); -} - -/* (:self) */ -static node* -new_self(parser_state *p) -{ - return list1((node*)NODE_SELF); -} - -/* (:call a b c) */ -static node* -new_call(parser_state *p, node *a, mrb_sym b, node *c) -{ - node *n = list4((node*)NODE_CALL, a, nsym(b), c); - NODE_LINENO(n, a); - return n; -} - -/* (:fcall self mid args) */ -static node* -new_fcall(parser_state *p, mrb_sym b, node *c) -{ - node *n = new_self(p); - NODE_LINENO(n, c); - n = list4((node*)NODE_FCALL, n, nsym(b), c); - NODE_LINENO(n, c); - return n; -} - -/* (:super . c) */ -static node* -new_super(parser_state *p, node *c) -{ - return cons((node*)NODE_SUPER, c); -} - -/* (:zsuper) */ -static node* -new_zsuper(parser_state *p) -{ - return list1((node*)NODE_ZSUPER); -} - -/* (:yield . c) */ -static node* -new_yield(parser_state *p, node *c) -{ - if (c) { - if (c->cdr) { - yyerror(p, "both block arg and actual block given"); - } - return cons((node*)NODE_YIELD, c->car); - } - return cons((node*)NODE_YIELD, 0); -} - -/* (:return . c) */ -static node* -new_return(parser_state *p, node *c) -{ - return cons((node*)NODE_RETURN, c); -} - -/* (:break . c) */ -static node* -new_break(parser_state *p, node *c) -{ - return cons((node*)NODE_BREAK, c); -} - -/* (:next . c) */ -static node* -new_next(parser_state *p, node *c) -{ - return cons((node*)NODE_NEXT, c); -} - -/* (:redo) */ -static node* -new_redo(parser_state *p) -{ - return list1((node*)NODE_REDO); -} - -/* (:retry) */ -static node* -new_retry(parser_state *p) -{ - return list1((node*)NODE_RETRY); -} - -/* (: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) */ -static node* -new_dot3(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_DOT3, cons(a, b)); -} - -/* (: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) */ -static node* -new_colon3(parser_state *p, mrb_sym c) -{ - return cons((node*)NODE_COLON3, nsym(c)); -} - -/* (: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) */ -static node* -new_or(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_OR, cons(a, b)); -} - -/* (:array a...) */ -static node* -new_array(parser_state *p, node *a) -{ - return cons((node*)NODE_ARRAY, a); -} - -/* (:splat . a) */ -static node* -new_splat(parser_state *p, node *a) -{ - return cons((node*)NODE_SPLAT, a); -} - -/* (:hash (k . v) (k . v)...) */ -static node* -new_hash(parser_state *p, node *a) -{ - return cons((node*)NODE_HASH, a); -} - -/* (:sym . a) */ -static node* -new_sym(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_SYM, nsym(sym)); -} - -static mrb_sym -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_intern(p->mrb, s, len); -} - -/* (:lvar . a) */ -static node* -new_lvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_LVAR, nsym(sym)); -} - -/* (:gvar . a) */ -static node* -new_gvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_GVAR, nsym(sym)); -} - -/* (:ivar . a) */ -static node* -new_ivar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_IVAR, nsym(sym)); -} - -/* (:cvar . a) */ -static node* -new_cvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_CVAR, nsym(sym)); -} - -/* (:const . a) */ -static node* -new_const(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_CONST, nsym(sym)); -} - -/* (:undef a...) */ -static node* -new_undef(parser_state *p, mrb_sym sym) -{ - return list2((node*)NODE_UNDEF, nsym(sym)); -} - -/* (: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(locals_node(p), b)); -} - -/* (:sclass obj body) */ -static node* -new_sclass(parser_state *p, node *o, node *b) -{ - return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b)); -} - -/* (:module module body) */ -static node* -new_module(parser_state *p, node *m, node *b) -{ - return list3((node*)NODE_MODULE, m, cons(locals_node(p), b)); -} - -/* (: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), locals_node(p), a, b); -} - -/* (: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), locals_node(p), a, b); -} - -/* (: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 */ -static node* -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) -{ - node *n; - - n = cons(m2, nsym(blk)); - n = cons(nsym(rest), n); - n = cons(opt, n); - return cons(m, n); -} - -/* (:block_arg . a) */ -static node* -new_block_arg(parser_state *p, node *a) -{ - return cons((node*)NODE_BLOCK_ARG, a); -} - -/* (:block arg body) */ -static node* -new_block(parser_state *p, node *a, node *b) -{ - return list4((node*)NODE_BLOCK, locals_node(p), a, b); -} - -/* (:lambda arg body) */ -static node* -new_lambda(parser_state *p, node *a, node *b) -{ - return list4((node*)NODE_LAMBDA, locals_node(p), a, b); -} - -/* (: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) */ -static node* -new_masgn(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_MASGN, cons(a, b)); -} - -/* (: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) */ -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) */ -static node* -new_float(parser_state *p, const char *s) -{ - return cons((node*)NODE_FLOAT, (node*)strdup(s)); -} - -/* (: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) */ -static node* -new_dstr(parser_state *p, node *a) -{ - return cons((node*)NODE_DSTR, a); -} - -/* (: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) */ -static node* -new_dxstr(parser_state *p, node *a) -{ - return cons((node*)NODE_DXSTR, a); -} - -/* (:dsym . a) */ -static node* -new_dsym(parser_state *p, node *a) -{ - return cons((node*)NODE_DSYM, new_dstr(p, 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) */ -static node* -new_dregx(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_DREGX, cons(a, b)); -} - -/* (:backref . n) */ -static node* -new_back_ref(parser_state *p, int n) -{ - return cons((node*)NODE_BACK_REF, (node*)(intptr_t)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) */ -static node* -new_heredoc(parser_state *p) -{ - parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info)); - return cons((node*)NODE_HEREDOC, (node*)inf); -} - -static void -new_bv(parser_state *p, mrb_sym id) -{ -} - -static node* -new_literal_delim(parser_state *p) -{ - return cons((node*)NODE_LITERAL_DELIM, 0); -} - -/* (:words . a) */ -static node* -new_words(parser_state *p, node *a) -{ - return cons((node*)NODE_WORDS, a); -} - -/* (:symbols . a) */ -static node* -new_symbols(parser_state *p, node *a) -{ - return cons((node*)NODE_SYMBOLS, a); -} - -/* xxx ----------------------------- */ - -/* (:call a op) */ -static node* -call_uni_op(parser_state *p, node *recv, const char *m) -{ - return new_call(p, recv, intern_cstr(m), 0); -} - -/* (:call a op b) */ -static node* -call_bin_op(parser_state *p, node *recv, const char *m, node *arg1) -{ - return new_call(p, recv, intern_cstr(m), list1(list1(arg1))); -} - -static void -args_with_block(parser_state *p, node *a, node *b) -{ - if (b) { - if (a->cdr) { - yyerror(p, "both block arg and actual block given"); - } - a->cdr = b; - } -} - -static void -call_with_block(parser_state *p, node *a, node *b) -{ - node *n; - - if (a->car == (node*)NODE_SUPER || - a->car == (node*)NODE_ZSUPER) { - if (!a->cdr) a->cdr = cons(0, b); - else { - args_with_block(p, a->cdr, b); - } - } - else { - n = a->cdr->cdr->cdr; - if (!n->car) n->car = cons(0, b); - else { - args_with_block(p, n->car, b); - } - } -} - -static node* -negate_lit(parser_state *p, node *n) -{ - return cons((node*)NODE_NEGATE, n); -} - -static node* -cond(node *n) -{ - return n; -} - -static node* -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); -} - -static void -assignable(parser_state *p, node *lhs) -{ - if ((int)(intptr_t)lhs->car == NODE_LVAR) { - local_add(p, sym(lhs->cdr)); - } -} - -static node* -var_reference(parser_state *p, node *lhs) -{ - node *n; - - if ((int)(intptr_t)lhs->car == NODE_LVAR) { - if (!local_var_p(p, sym(lhs->cdr))) { - n = new_fcall(p, sym(lhs->cdr), 0); - cons_free(lhs); - return n; - } - } - - return lhs; -} - -typedef enum mrb_string_type string_type; - -static node* -new_strterm(parser_state *p, string_type type, int term, int paren) -{ - return cons((node*)(intptr_t)type, cons((node*)0, cons((node*)(intptr_t)paren, (node*)(intptr_t)term))); -} - -static void -end_strterm(parser_state *p) -{ - cons_free(p->lex_strterm->cdr->cdr); - cons_free(p->lex_strterm->cdr); - cons_free(p->lex_strterm); - p->lex_strterm = NULL; -} - -static parser_heredoc_info * -parsing_heredoc_inf(parser_state *p) -{ - node *nd = p->parsing_heredoc; - if (nd == NULL) - return NULL; - /* mrb_assert(nd->car->car == NODE_HEREDOC); */ - return (parser_heredoc_info*)nd->car->cdr; -} - -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; - if (p->parsing_heredoc == NULL) { - 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 { - /* 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 ----------------------------- */ - -%} - -%pure-parser -%parse-param {parser_state *p} -%lex-param {parser_state *p} - -%union { - node *nd; - mrb_sym id; - int num; - stack_type stack; - const struct vtable *vars; -} - -%token <num> - keyword_class - keyword_module - keyword_def - keyword_begin - keyword_if - keyword_unless - keyword_while - keyword_until - keyword_for - -%token - keyword_undef - keyword_rescue - keyword_ensure - keyword_end - keyword_then - keyword_elsif - keyword_else - keyword_case - keyword_when - 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 -%token <nd> tSTRING tSTRING_PART tSTRING_MID -%token <nd> tNTH_REF tBACK_REF -%token <num> tREGEXP_END - -%type <nd> singleton string string_rep string_interp xstring regexp -%type <nd> literal numeric cpath symbol -%type <nd> top_compstmt top_stmts top_stmt -%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call -%type <nd> expr_value arg_value primary_value -%type <nd> if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure -%type <nd> args call_args opt_call_args -%type <nd> paren_args opt_paren_args variable -%type <nd> command_args aref_args opt_block_arg block_arg var_ref var_lhs -%type <nd> command_asgn mrhs superclass block_call block_command -%type <nd> f_block_optarg f_block_opt -%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs -%type <nd> assoc_list assocs assoc undef_list backref for_var -%type <nd> block_param opt_block_param block_param_def f_opt -%type <nd> bv_decls opt_bv_decl bvar f_larglist lambda_body -%type <nd> brace_block cmd_brace_block do_block lhs none f_bad_arg -%type <nd> mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner -%type <id> fsym sym basic_symbol operation operation2 operation3 -%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn -%type <nd> heredoc words symbols - -%token tUPLUS /* unary+ */ -%token tUMINUS /* unary- */ -%token tPOW /* ** */ -%token tCMP /* <=> */ -%token tEQ /* == */ -%token tEQQ /* === */ -%token tNEQ /* != */ -%token tGEQ /* >= */ -%token tLEQ /* <= */ -%token tANDOP tOROP /* && and || */ -%token tMATCH tNMATCH /* =~ and !~ */ -%token tDOT2 tDOT3 /* .. and ... */ -%token tAREF tASET /* [] and []= */ -%token tLSHFT tRSHFT /* << and >> */ -%token tCOLON2 /* :: */ -%token tCOLON3 /* :: at EXPR_BEG */ -%token <id> tOP_ASGN /* +=, -= etc. */ -%token tASSOC /* => */ -%token tLPAREN /* ( */ -%token tLPAREN_ARG /* ( */ -%token tRPAREN /* ) */ -%token tLBRACK /* [ */ -%token tLBRACE /* { */ -%token tLBRACE_ARG /* { */ -%token tSTAR /* * */ -%token tAMPER /* & */ -%token tLAMBDA /* -> */ -%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 tHD_LITERAL_DELIM -%token <nd> tHD_STRING_PART tHD_STRING_MID - -/* - * precedence table - */ - -%nonassoc tLOWEST -%nonassoc tLBRACE_ARG - -%nonassoc modifier_if modifier_unless modifier_while modifier_until -%left keyword_or keyword_and -%right keyword_not -%right '=' tOP_ASGN -%left modifier_rescue -%right '?' ':' -%nonassoc tDOT2 tDOT3 -%left tOROP -%left tANDOP -%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH -%left '>' tGEQ '<' tLEQ -%left '|' '^' -%left '&' -%left tLSHFT tRSHFT -%left '+' '-' -%left '*' '/' '%' -%right tUMINUS_NUM tUMINUS -%right tPOW -%right '!' '~' tUPLUS - -%token tLAST_TOKEN - -%% -program : { - p->lstate = EXPR_BEG; - if (!p->locals) p->locals = cons(0,0); - } - top_compstmt - { - p->tree = new_scope(p, $2); - NODE_LINENO(p->tree, $2); - } - ; - -top_compstmt : top_stmts opt_terms - { - $$ = $1; - } - ; - -top_stmts : none - { - $$ = new_begin(p, 0); - } - | top_stmt - { - $$ = new_begin(p, $1); - NODE_LINENO($$, $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); - NODE_LINENO($$, $1); - } - 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); - NODE_LINENO($$, $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 - { - $$ = $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 - { - $$ = new_masgn(p, $2, NULL); - } - ; - -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; - NODE_LINENO($$, $1); - } - | args ',' assocs trailer - { - $$ = push($1, new_hash(p, $3)); - } - | assocs trailer - { - $$ = cons(new_hash(p, $1), 0); - NODE_LINENO($$, $1); - } - ; - -paren_args : '(' opt_call_args rparen - { - $$ = $2; - } - ; - -opt_paren_args : none - | paren_args - ; - -opt_call_args : none - | call_args - | args ',' - { - $$ = cons($1,0); - NODE_LINENO($$, $1); - } - | args ',' assocs ',' - { - $$ = cons(push($1, new_hash(p, $3)), 0); - NODE_LINENO($$, $1); - } - | assocs ',' - { - $$ = cons(list1(new_hash(p, $1)), 0); - NODE_LINENO($$, $1); - } - ; - -call_args : command - { - $$ = cons(list1($1), 0); - NODE_LINENO($$, $1); - } - | args opt_block_arg - { - $$ = cons($1, $2); - NODE_LINENO($$, $1); - } - | assocs opt_block_arg - { - $$ = cons(list1(new_hash(p, $1)), $2); - NODE_LINENO($$, $1); - } - | args ',' assocs opt_block_arg - { - $$ = cons(push($1, new_hash(p, $3)), $4); - NODE_LINENO($$, $1); - } - | block_arg - { - $$ = cons(0, $1); - NODE_LINENO($$, $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); - NODE_LINENO($$, $1); - } - | tSTAR arg_value - { - $$ = cons(new_splat(p, $2), 0); - NODE_LINENO($$, $2); - } - | 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>$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - bodystmt - keyword_end - { - p->cmdarg_stack = $<stack>2; - $$ = $3; - } - | tLPAREN_ARG - { - $<stack>$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - expr {p->lstate = EXPR_ENDARG;} rparen - { - p->cmdarg_stack = $<stack>2; - $$ = $3; - } - | 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); - NODE_LINENO($$, $2); - } - | tLBRACE assoc_list '}' - { - $$ = new_hash(p, $2); - NODE_LINENO($$, $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 - { - $<stack>$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - lambda_body - { - p->lpar_beg = $<num>2; - $$ = new_lambda(p, $3, $5); - local_unnest(p); - p->cmdarg_stack = $<stack>4; - } - | keyword_if expr_value then - compstmt - if_tail - keyword_end - { - $$ = new_if(p, cond($2), $4, $5); - SET_LINENO($$, $1); - } - | keyword_unless expr_value then - compstmt - opt_else - keyword_end - { - $$ = new_unless(p, cond($2), $4, $5); - SET_LINENO($$, $1); - } - | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_while(p, cond($3), $6); - SET_LINENO($$, $1); - } - | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_until(p, cond($3), $6); - SET_LINENO($$, $1); - } - | 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); - SET_LINENO($$, $1); - } - | 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); - SET_LINENO($$, $1); - 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); - SET_LINENO($$, $1); - 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); - SET_LINENO($$, $1); - local_resume(p, $<nd>3); - } - | keyword_def fname - { - $<stack>$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - { - p->in_def++; - $<nd>$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_def(p, $2, $5, $6); - SET_LINENO($$, $1); - local_resume(p, $<nd>4); - p->in_def--; - p->cmdarg_stack = $<stack>3; - } - | keyword_def singleton dot_or_colon - { - p->lstate = EXPR_FNAME; - $<stack>$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - 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); - SET_LINENO($$, $1); - local_resume(p, $<nd>6); - p->in_single--; - p->cmdarg_stack = $<stack>4; - } - | 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 '|' - { - $$ = 0; - } - | tOROP - { - $$ = 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)); - } - | 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_asgn : tIDENTIFIER '=' - { - local_add_f(p, $1); - $$ = $1; - } - ; - -f_opt : f_opt_asgn arg_value - { - $$ = cons(nsym($1), $2); - } - ; - -f_block_opt : f_opt_asgn primary_value - { - $$ = cons(nsym($1), $2); - } - ; - -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); - NODE_LINENO($$, $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))) - -static void -yyerror(parser_state *p, const char *s) -{ - char* c; - int n; - - if (! p->capture_errors) { -#ifdef ENABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); - } - else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); - } -#endif - } - else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) { - n = strlen(s); - c = (char *)parser_palloc(p, n + 1); - memcpy(c, s, n + 1); - p->error_buffer[p->nerr].message = c; - p->error_buffer[p->nerr].lineno = p->lineno; - p->error_buffer[p->nerr].column = p->column; - } - p->nerr++; -} - -static void -yyerror_i(parser_state *p, const char *fmt, int i) -{ - char buf[256]; - - snprintf(buf, sizeof(buf), fmt, i); - yyerror(p, buf); -} - -static void -yywarn(parser_state *p, const char *s) -{ - char* c; - int n; - - if (! p->capture_errors) { -#ifdef ENABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); - } - else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); - } -#endif - } - else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) { - n = strlen(s); - c = (char *)parser_palloc(p, n + 1); - memcpy(c, s, n + 1); - p->warn_buffer[p->nwarn].message = c; - p->warn_buffer[p->nwarn].lineno = p->lineno; - p->warn_buffer[p->nwarn].column = p->column; - } - p->nwarn++; -} - -static void -yywarning(parser_state *p, const char *s) -{ - yywarn(p, s); -} - -static void -yywarning_s(parser_state *p, const char *fmt, const char *s) -{ - char buf[256]; - - snprintf(buf, sizeof(buf), fmt, s); - yywarning(p, buf); -} - -static void -backref_error(parser_state *p, node *n) -{ - int c; - - c = (int)(intptr_t)n->car; - - if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr); - } - 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 == %S", mrb_fixnum_value(c)); - } -} - -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) -{ - int c; - - if (p->pb) { - node *tmp; - - c = (int)(intptr_t)p->pb->car; - tmp = p->pb; - p->pb = p->pb->cdr; - cons_free(tmp); - } - else { -#ifdef ENABLE_STDIO - if (p->f) { - if (feof(p->f)) goto eof; - c = fgetc(p->f); - if (c == EOF) goto eof; - } - else -#endif - if (!p->s || p->s >= p->send) { - goto eof; - } - else { - c = (unsigned char)*p->s++; - } - } - if (c >= 0) { - p->column++; - } - if (c == '\r') { - c = nextc(p); - if (c != '\n') { - pushback(p, c); - return '\r'; - } - return c; - } - return c; - - eof: - if (!p->cxt) return -1; - else { - if (p->cxt->partial_hook(p) < 0) - return -1; /* end of program(s) */ - return -2; /* end of a file in the program files */ - } -} - -static void -pushback(parser_state *p, int c) -{ - if (c >= 0) { - p->column--; - } - p->pb = cons((node*)(intptr_t)c, p->pb); -} - -static void -skip(parser_state *p, char term) -{ - int c; - - for (;;) { - c = nextc(p); - if (c < 0) break; - if (c == term) break; - } -} - -static int -peekc_n(parser_state *p, int n) -{ - node *list = 0; - int c0; - - do { - c0 = nextc(p); - if (c0 == -1) return c0; /* do not skip partial EOF */ - list = push(list, (node*)(intptr_t)c0); - } while(n--); - if (p->pb) { - p->pb = append((node*)list, p->pb); - } - else { - p->pb = list; - } - return c0; -} - -static mrb_bool -peek_n(parser_state *p, int c, int n) -{ - return peekc_n(p, n) == c && c >= 0; -} -#define peek(p,c) peek_n((p), (c), 0) - -static mrb_bool -peeks(parser_state *p, const char *s) -{ - int len = strlen(s); - -#ifdef ENABLE_STDIO - if (p->f) { - int n = 0; - while (*s) { - if (!peek_n(p, *s++, n++)) return FALSE; - } - return TRUE; - } - else -#endif - if (p->s && p->s + len <= p->send) { - if (memcmp(p->s, s, len) == 0) return TRUE; - } - return FALSE; -} - -static mrb_bool -skips(parser_state *p, const char *s) -{ - int c; - - for (;;) { - /* skip until first char */ - for (;;) { - c = nextc(p); - if (c < 0) return c; - if (c == '\n') { - p->lineno++; - p->column = 0; - } - if (c == *s) break; - } - s++; - if (peeks(p, s)) { - int len = strlen(s); - - while (len--) { - if (nextc(p) == '\n') { - p->lineno++; - p->column = 0; - } - } - return TRUE; - } - else{ - s--; - } - } - return FALSE; -} - - -static int -newtok(parser_state *p) -{ - p->bidx = 0; - return p->column - 1; -} - -static void -tokadd(parser_state *p, int32_t 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]; - } - } -} - -static int -toklast(parser_state *p) -{ - return p->buf[p->bidx-1]; -} - -static void -tokfix(parser_state *p) -{ - if (p->bidx >= MRB_PARSER_BUF_SIZE) { - yyerror(p, "string too long (truncated)"); - } - p->buf[p->bidx] = '\0'; -} - -static const char* -tok(parser_state *p) -{ - return p->buf; -} - -static int -toklen(parser_state *p) -{ - return p->bidx; -} - -#define IS_ARG() (p->lstate == EXPR_ARG || p->lstate == EXPR_CMDARG) -#define IS_END() (p->lstate == EXPR_END || p->lstate == EXPR_ENDARG || p->lstate == EXPR_ENDFN) -#define IS_BEG() (p->lstate == EXPR_BEG || p->lstate == EXPR_MID || p->lstate == EXPR_VALUE || p->lstate == EXPR_CLASS) -#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c)) -#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG()) -#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1)) - -static int -scan_oct(const int *start, int len, int *retlen) -{ - const int *s = start; - int retval = 0; - - /* mrb_assert(len <= 3) */ - while (len-- && *s >= '0' && *s <= '7') { - retval <<= 3; - retval |= *s++ - '0'; - } - *retlen = s - start; - - return retval; -} - -static int32_t -scan_hex(const int *start, int len, int *retlen) -{ - static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; - const int *s = start; - int32_t retval = 0; - char *tmp; - - /* mrb_assert(len <= 8) */ - while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { - retval <<= 4; - retval |= (tmp - hexdigit) & 15; - s++; - } - *retlen = s - start; - - return retval; -} - -/* Return negative to indicate Unicode code point */ -static int32_t -read_escape(parser_state *p) -{ - int32_t c; - - switch (c = nextc(p)) { - case '\\':/* Backslash */ - return c; - - case 'n':/* newline */ - return '\n'; - - case 't':/* horizontal tab */ - return '\t'; - - case 'r':/* carriage-return */ - return '\r'; - - case 'f':/* form-feed */ - return '\f'; - - case 'v':/* vertical tab */ - return '\13'; - - case 'a':/* alarm(bell) */ - return '\007'; - - 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; - - 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] < 0) goto eof; - if (buf[i] == '}') { - break; - } - else if (!ISXDIGIT(buf[i])) { - yyerror(p, "Invalid escape character syntax"); - pushback(p, buf[i]); - 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; - } - } - } - 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 */ - return '\010'; - - case 's':/* space */ - return ' '; - - case 'M': - if ((c = nextc(p)) != '-') { - yyerror(p, "Invalid escape character syntax"); - pushback(p, c); - return '\0'; - } - if ((c = nextc(p)) == '\\') { - return read_escape(p) | 0x80; - } - else if (c < 0) goto eof; - else { - return ((c & 0xff) | 0x80); - } - - case 'C': - if ((c = nextc(p)) != '-') { - yyerror(p, "Invalid escape character syntax"); - pushback(p, c); - return '\0'; - } - case 'c': - if ((c = nextc(p))== '\\') { - c = read_escape(p); - } - else if (c == '?') - return 0177; - else if (c < 0) goto eof; - return c & 0x9f; - - eof: - case -1: - case -2: /* end of a file */ - yyerror(p, "Invalid escape character syntax"); - return '\0'; - - default: - return c; - } -} - -static int -parse_string(parser_state *p) -{ - int c; - string_type type = (string_type)(intptr_t)p->lex_strterm->car; - int nest_level = (intptr_t)p->lex_strterm->cdr->car; - int beg = (intptr_t)p->lex_strterm->cdr->cdr->car; - int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr; - parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL; - - newtok(p); - while ((c = nextc(p)) != end || nest_level != 0) { - if (hinf && (c == '\n' || c < 0)) { - mrb_bool line_head; - tokadd(p, '\n'); - tokfix(p); - p->lineno++; - p->column = 0; - 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; - } - } - 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 tHD_STRING_MID; - } - if (c < 0) { - yyerror(p, "unterminated string meets end of file"); - return 0; - } - else if (c == beg) { - nest_level++; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; - } - else if (c == end) { - nest_level--; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; - } - else if (c == '\\') { - c = nextc(p); - if (type & STR_FUNC_EXPAND) { - 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 tHD_STRING_PART; - } - return tSTRING_PART; - } - tokadd(p, '#'); - pushback(p, c); - continue; - } - if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { - if (toklen(p) == 0) { - do { - if (c == '\n') { - p->lineno++; - p->column = 0; - heredoc_treat_nextline(p); - if (p->parsing_heredoc != NULL) { - return tHD_LITERAL_DELIM; - } - } - c = nextc(p); - } while (ISSPACE(c)); - 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); - p->lstate = EXPR_END; - end_strterm(p); - - if (type & STR_FUNC_XQUOTE) { - yylval.nd = new_xstr(p, tok(p), toklen(p)); - return tXSTRING; - } - - if (type & STR_FUNC_REGEXP) { - int f = 0; - int re_opt; - char *s = strndup(tok(p), toklen(p)); - char flags[3]; - char *flag = flags; - char *dup; - - newtok(p); - while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) { - switch (re_opt) { - case 'i': f |= 1; break; - case 'x': f |= 2; break; - case 'm': f |= 4; break; - default: tokadd(p, re_opt); break; - } - } - pushback(p, re_opt); - if (toklen(p)) { - char msg[128]; - tokfix(p); - snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); - yyerror(p, msg); - } - 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; - } - - yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING; -} - - -static int -heredoc_identifier(parser_state *p) -{ - int c; - int type = str_heredoc; - mrb_bool indent = FALSE; - mrb_bool quote = FALSE; - node *newnode; - parser_heredoc_info *info; - - c = nextc(p); - if (ISSPACE(c) || c == '=') { - pushback(p, c); - return 0; - } - if (c == '-') { - indent = TRUE; - c = nextc(p); - } - if (c == '\'' || c == '"') { - int term = c; - if (c == '\'') - quote = TRUE; - newtok(p); - while ((c = nextc(p)) >= 0 && c != term) { - if (c == '\n') { - c = -1; - break; - } - tokadd(p, c); - } - if (c < 0) { - yyerror(p, "unterminated here document identifier"); - return 0; - } - } - else { - if (c < 0) { - return 0; /* missing here document identifier */ - } - if (! identchar(c)) { - pushback(p, c); - if (indent) pushback(p, '-'); - return 0; - } - newtok(p); - do { - tokadd(p, c); - } while ((c = nextc(p)) >= 0 && identchar(c)); - pushback(p, c); - } - tokfix(p); - newnode = new_heredoc(p); - info = (parser_heredoc_info*)newnode->cdr; - info->term = strndup(tok(p), toklen(p)); - info->term_len = toklen(p); - if (! quote) - type |= STR_FUNC_EXPAND; - info->type = (string_type)type; - info->allow_indent = indent; - info->line_head = TRUE; - info->doc = NULL; - p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode); - p->lstate = EXPR_END; - - yylval.nd = newnode; - return tHEREDOC_BEG; -} - -static int -arg_ambiguous(parser_state *p) -{ - yywarning(p, "ambiguous first argument; put parentheses or even spaces"); - return 1; -} - -#include "lex.def" - -static int -parser_yylex(parser_state *p) -{ - int32_t c; - int space_seen = 0; - int cmd_state; - enum mrb_lex_state_enum last_state; - int token_column; - - if (p->lex_strterm) { - if (is_strterm_type(p, STR_FUNC_HEREDOC)) { - if (p->parsing_heredoc != NULL) - return parse_string(p); - } - else - return parse_string(p); - } - cmd_state = p->cmd_start; - p->cmd_start = FALSE; - retry: - last_state = p->lstate; - switch (c = nextc(p)) { - case '\004': /* ^D */ - case '\032': /* ^Z */ - case '\0': /* NUL */ - case -1: /* end of script. */ - if (p->heredocs_from_nextline) - goto maybe_heredoc; - return 0; - - /* white spaces */ - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - goto retry; - - case '#': /* it's a comment */ - skip(p, '\n'); - /* fall through */ - case -2: /* end of a file */ - case '\n': - 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) { - if (p->lex_strterm) { - return parse_string(p); - } - } - 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; - case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); - pushback(p, '.'); - goto retry; - } - case -1: /* EOF */ - case -2: /* end of a file */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; - } - } - normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; - - case '*': - if ((c = nextc(p)) == '*') { - if ((c = nextc(p)) == '=') { - 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; - } - pushback(p, c); - if (IS_SPCARG(c)) { - yywarning(p, "`*' interpreted as argument prefix"); - c = tSTAR; - } - else if (IS_BEG()) { - c = tSTAR; - } - else { - c = '*'; - } - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return c; - - case '!': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return '!'; - } - } - else { - p->lstate = EXPR_BEG; - } - if (c == '=') { - return tNEQ; - } - if (c == '~') { - return tNMATCH; - } - pushback(p, c); - return '!'; - - case '=': - if (p->column == 1) { - static const char begin[] = "begin"; - static const char end[] = "\n=end"; - if (peeks(p, begin)) { - c = peekc_n(p, sizeof(begin)-1); - if (c < 0 || ISSPACE(c)) { - do { - if (!skips(p, end)) { - yyerror(p, "embedded document meets end of file"); - return 0; - } - c = nextc(p); - } while (!(c < 0 || ISSPACE(c))); - if (c != '\n') skip(p, '\n'); - p->lineno++; - p->column = 0; - goto retry; - } - } - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - if ((c = nextc(p)) == '=') { - if ((c = nextc(p)) == '=') { - return tEQQ; - } - pushback(p, c); - return tEQ; - } - if (c == '~') { - return tMATCH; - } - else if (c == '>') { - return tASSOC; - } - pushback(p, c); - return '='; - - case '<': - c = nextc(p); - if (c == '<' && - p->lstate != EXPR_DOT && - p->lstate != EXPR_CLASS && - !IS_END() && - (!IS_ARG() || space_seen)) { - int token = heredoc_identifier(p); - if (token) - return token; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - if (p->lstate == EXPR_CLASS) { - p->cmd_start = TRUE; - } - } - if (c == '=') { - if ((c = nextc(p)) == '>') { - return tCMP; - } - pushback(p, c); - return tLEQ; - } - if (c == '<') { - if ((c = nextc(p)) == '=') { - yylval.id = intern("<<",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tLSHFT; - } - pushback(p, c); - return '<'; - - case '>': - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - if ((c = nextc(p)) == '=') { - return tGEQ; - } - if (c == '>') { - if ((c = nextc(p)) == '=') { - yylval.id = intern(">>",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tRSHFT; - } - pushback(p, c); - return '>'; - - case '"': - p->lex_strterm = new_strterm(p, str_dquote, '"', 0); - return tSTRING_BEG; - - case '\'': - p->lex_strterm = new_strterm(p, str_squote, '\'', 0); - return parse_string(p); - - case '`': - if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; - return '`'; - } - if (p->lstate == EXPR_DOT) { - if (cmd_state) - p->lstate = EXPR_CMDARG; - else - p->lstate = EXPR_ARG; - return '`'; - } - p->lex_strterm = new_strterm(p, str_xquote, '`', 0); - return tXSTRING_BEG; - - case '?': - if (IS_END()) { - p->lstate = EXPR_VALUE; - return '?'; - } - c = nextc(p); - 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); - } - } - ternary: - pushback(p, c); - p->lstate = EXPR_VALUE; - return '?'; - } - newtok(p); - /* need support UTF-8 if configured */ - if ((isalnum(c) || c == '_')) { - int c2 = nextc(p); - pushback(p, c2); - if ((isalnum(c2) || c2 == '_')) { - goto ternary; - } - } - if (c == '\\') { - c = read_escape(p); - tokadd(p, c); - } - else { - tokadd(p, c); - } - tokfix(p); - yylval.nd = new_str(p, tok(p), toklen(p)); - p->lstate = EXPR_END; - return tCHAR; - - case '&': - if ((c = nextc(p)) == '&') { - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '=') { - yylval.id = intern("&&",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tANDOP; - } - else if (c == '=') { - 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 = tAMPER; - } - else if (IS_BEG()) { - c = tAMPER; - } - else { - c = '&'; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return c; - - case '|': - if ((c = nextc(p)) == '|') { - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '=') { - yylval.id = intern("||",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tOROP; - } - if (c == '=') { - yylval.id = intern_c('|'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '|'; - - case '+': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return tUPLUS; - } - pushback(p, c); - return '+'; - } - if (c == '=') { - yylval.id = intern_c('+'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { - p->lstate = EXPR_BEG; - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - c = '+'; - goto start_num; - } - return tUPLUS; - } - p->lstate = EXPR_BEG; - pushback(p, c); - return '+'; - - case '-': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return tUMINUS; - } - pushback(p, c); - return '-'; - } - if (c == '=') { - yylval.id = intern_c('-'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (c == '>') { - p->lstate = EXPR_ENDFN; - return tLAMBDA; - } - if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { - p->lstate = EXPR_BEG; - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - return tUMINUS_NUM; - } - return tUMINUS; - } - p->lstate = EXPR_BEG; - pushback(p, c); - return '-'; - - case '.': - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '.') { - if ((c = nextc(p)) == '.') { - return tDOT3; - } - pushback(p, c); - return tDOT2; - } - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - yyerror(p, "no .<digit> floating literal anymore; put 0 before dot"); - } - p->lstate = EXPR_DOT; - return '.'; - - 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; - - is_float = seen_point = seen_e = nondigit = 0; - p->lstate = EXPR_END; - 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 >= 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 < 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) { - trailing_uc: - 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)); - } - 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; - } - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; - } - - case ')': - case ']': - p->paren_nest--; - case '}': - COND_LEXPOP(); - CMDARG_LEXPOP(); - if (c == ')') - p->lstate = EXPR_ENDFN; - else - p->lstate = EXPR_ENDARG; - return c; - - case ':': - c = nextc(p); - if (c == ':') { - if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { - p->lstate = EXPR_BEG; - return tCOLON3; - } - p->lstate = EXPR_DOT; - return tCOLON2; - } - if (IS_END() || ISSPACE(c)) { - pushback(p, c); - p->lstate = EXPR_BEG; - return ':'; - } - pushback(p, c); - p->lstate = EXPR_FNAME; - return tSYMBEG; - - case '/': - if (IS_BEG()) { - p->lex_strterm = new_strterm(p, str_regexp, '/', 0); - return tREGEXP_BEG; - } - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('/'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - if (IS_SPCARG(c)) { - p->lex_strterm = new_strterm(p, str_regexp, '/', 0); - return tREGEXP_BEG; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return '/'; - - case '^': - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('^'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '^'; - - case ';': - p->lstate = EXPR_BEG; - return ';'; - - case ',': - p->lstate = EXPR_BEG; - return ','; - - case '~': - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - if ((c = nextc(p)) != '@') { - pushback(p, c); - } - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return '~'; - - case '(': - if (IS_BEG()) { - c = tLPAREN; - } - else if (IS_SPCARG(-1)) { - c = tLPAREN_ARG; - } - p->paren_nest++; - COND_PUSH(0); - CMDARG_PUSH(0); - p->lstate = EXPR_BEG; - return c; - - case '[': - p->paren_nest++; - 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; - } - pushback(p, c); - return '['; - } - else if (IS_BEG()) { - c = tLBRACK; - } - else if (IS_ARG() && space_seen) { - c = tLBRACK; - } - p->lstate = EXPR_BEG; - COND_PUSH(0); - CMDARG_PUSH(0); - return c; - - case '{': - if (p->lpar_beg && p->lpar_beg == p->paren_nest) { - p->lstate = EXPR_BEG; - p->lpar_beg = 0; - p->paren_nest--; - COND_PUSH(0); - CMDARG_PUSH(0); - return tLAMBEG; - } - if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN) - c = '{'; /* block (primary) */ - else if (p->lstate == EXPR_ENDARG) - c = tLBRACE_ARG; /* block (expr) */ - else - c = tLBRACE; /* hash */ - COND_PUSH(0); - CMDARG_PUSH(0); - p->lstate = EXPR_BEG; - return c; - - case '\\': - c = nextc(p); - if (c == '\n') { - p->lineno++; - p->column = 0; - space_seen = 1; - goto retry; /* skip \\n */ - } - pushback(p, c); - return '\\'; - - case '%': - if (IS_BEG()) { - int term; - int paren; - - c = nextc(p); - 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; - } - } - if (c < 0 || term < 0) { - yyerror(p, "unterminated quoted string meets end of file"); - return 0; - } - paren = term; - if (term == '(') term = ')'; - else if (term == '[') term = ']'; - else if (term == '{') term = '}'; - else if (term == '<') term = '>'; - else paren = 0; - - switch (c) { - case 'Q': - 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); - - case 'W': - 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; - - case 'x': - 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; - - case 's': - 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; - - case 'i': - p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); - return tSYMBOLS_BEG; - - default: - yyerror(p, "unknown type of %string"); - return 0; - } - } - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('%'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (IS_SPCARG(c)) { - goto quotation; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '%'; - - case '$': - p->lstate = EXPR_END; - token_column = newtok(p); - c = nextc(p); - if (c < 0) { - yyerror(p, "incomplete global variable syntax"); - return 0; - } - switch (c) { - case '_': /* $_: last read line string */ - c = nextc(p); - if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ - tokadd(p, '$'); - tokadd(p, c); - break; - } - pushback(p, c); - c = '_'; - /* fall through */ - case '~': /* $~: match-data */ - case '*': /* $*: argv */ - case '$': /* $$: pid */ - case '?': /* $?: last status */ - case '!': /* $!: error string */ - case '@': /* $@: error position */ - case '/': /* $/: input record separator */ - case '\\': /* $\: output record separator */ - case ';': /* $;: field separator */ - case ',': /* $,: output field separator */ - case '.': /* $.: last read line number */ - case '=': /* $=: ignorecase */ - case ':': /* $:: load path */ - case '<': /* $<: reading filename */ - case '>': /* $>: default output handle */ - case '\"': /* $": already loaded files */ - tokadd(p, '$'); - tokadd(p, c); - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tGVAR; - - case '-': - tokadd(p, '$'); - tokadd(p, c); - c = nextc(p); - pushback(p, c); - gvar: - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tGVAR; - - case '&': /* $&: last match */ - case '`': /* $`: string before last match */ - case '\'': /* $': string after last match */ - case '+': /* $+: string matches last pattern */ - if (last_state == EXPR_FNAME) { - tokadd(p, '$'); - tokadd(p, c); - goto gvar; - } - yylval.nd = new_back_ref(p, c); - return tBACK_REF; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - do { - tokadd(p, c); - c = nextc(p); - } while (c >= 0 && isdigit(c)); - pushback(p, c); - if (last_state == EXPR_FNAME) goto gvar; - tokfix(p); - { - unsigned long n = strtoul(tok(p), NULL, 10); - if (n > INT_MAX) { - yyerror_i(p, "capture group index must be <= %d", INT_MAX); - return 0; - } - yylval.nd = new_nth_ref(p, (int)n); - } - return tNTH_REF; - - default: - if (!identchar(c)) { - pushback(p, c); - return '$'; - } - case '0': - tokadd(p, '$'); - } - break; - - case '@': - c = nextc(p); - token_column = newtok(p); - tokadd(p, '@'); - if (c == '@') { - tokadd(p, '@'); - c = nextc(p); - } - if (c < 0) { - if (p->bidx == 1) { - yyerror(p, "incomplete instance variable syntax"); - } - else { - yyerror(p, "incomplete class variable syntax"); - } - return 0; - } - 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; - } - if (!identchar(c)) { - pushback(p, c); - return '@'; - } - break; - - case '_': - token_column = newtok(p); - break; - - default: - if (!identchar(c)) { - yyerror_i(p, "Invalid char `\\x%02X' in expression", c); - goto retry; - } - - token_column = newtok(p); - break; - } - - do { - tokadd(p, c); - c = nextc(p); - if (c < 0) break; - } while (identchar(c)); - if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') && - strncmp(tok(p), "__END__", toklen(p)) == 0) - return -1; - - switch (tok(p)[0]) { - case '@': case '$': - pushback(p, c); - break; - default: - if ((c == '!' || c == '?') && !peek(p, '=')) { - tokadd(p, c); - } - else { - pushback(p, c); - } - } - tokfix(p); - { - int result = 0; - - switch (tok(p)[0]) { - case '$': - p->lstate = EXPR_END; - result = tGVAR; - break; - case '@': - p->lstate = EXPR_END; - if (tok(p)[1] == '@') - result = tCVAR; - else - result = tIVAR; - break; - - default: - if (toklast(p) == '!' || toklast(p) == '?') { - 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(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_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; - yylval.num = p->lineno; - 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; - } - } - else if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; - } - else { - p->lstate = EXPR_END; - } - } - { - 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; - } -#endif - } - return result; - } -} - -static int -yylex(void *lval, parser_state *p) -{ - p->ylval = lval; - return parser_yylex(p); -} - -static void -parser_init_cxt(parser_state *p, mrbc_context *cxt) -{ - if (!cxt) return; - if (cxt->filename) mrb_parser_set_filename(p, cxt->filename); - if (cxt->lineno) p->lineno = cxt->lineno; - if (cxt->syms) { - int i; - - p->locals = cons(0,0); - for (i=0; i<cxt->slen; i++) { - local_add_f(p, cxt->syms[i]); - } - } - p->capture_errors = cxt->capture_errors; - p->no_optimize = cxt->no_optimize; - if (cxt->partial_hook) { - p->cxt = cxt; - } -} - -static void -parser_update_cxt(parser_state *p, mrbc_context *cxt) -{ - node *n, *n0; - int i = 0; - - if (!cxt) return; - if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; - n0 = n = p->tree->cdr->car; - while (n) { - i++; - n = n->cdr; - } - cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym)); - cxt->slen = i; - for (i=0, n=n0; n; i++,n=n->cdr) { - cxt->syms[i] = sym(n->car); - } -} - -void mrb_codedump_all(mrb_state*, struct RProc*); -void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); - -MRB_API void -mrb_parser_parse(parser_state *p, mrbc_context *c) -{ - struct mrb_jmpbuf buf; - p->jmp = &buf; - - MRB_TRY(p->jmp) { - - p->cmd_start = TRUE; - p->in_def = p->in_single = 0; - p->nerr = p->nwarn = 0; - p->lex_strterm = NULL; - - parser_init_cxt(p, c); - yyparse(p); - if (!p->tree) { - p->tree = new_nil(p); - } - parser_update_cxt(p, c); - if (c && c->dump_result) { - 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); -} - -MRB_API parser_state* -mrb_parser_new(mrb_state *mrb) -{ - mrb_pool *pool; - parser_state *p; - static const parser_state parser_state_zero = { 0 }; - - pool = mrb_pool_open(mrb); - if (!pool) return NULL; - p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state)); - if (!p) return NULL; - - *p = parser_state_zero; - p->mrb = mrb; - p->pool = pool; - - p->s = p->send = NULL; -#ifdef ENABLE_STDIO - p->f = NULL; -#endif - - p->cmd_start = TRUE; - p->in_def = p->in_single = 0; - - p->capture_errors = FALSE; - p->lineno = 1; - p->column = 0; -#if defined(PARSER_TEST) || defined(PARSER_DEBUG) - yydebug = 1; -#endif - - p->lex_strterm = 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; -} - -MRB_API void -mrb_parser_free(parser_state *p) { - mrb_pool_close(p->pool); -} - -MRB_API mrbc_context* -mrbc_context_new(mrb_state *mrb) -{ - return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); -} - -MRB_API void -mrbc_context_free(mrb_state *mrb, mrbc_context *cxt) -{ - mrb_free(mrb, cxt->syms); - mrb_free(mrb, cxt); -} - -MRB_API const char* -mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) -{ - if (s) { - int len = strlen(s); - char *p = (char *)mrb_alloca(mrb, len + 1); - - memcpy(p, s, len + 1); - c->filename = p; - } - return c->filename; -} - -MRB_API void -mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data) -{ - c->partial_hook = func; - c->partial_data = data; -} - -MRB_API 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) { - memmove(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; -} - -MRB_API 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 -MRB_API parser_state* -mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) -{ - parser_state *p; - - p = mrb_parser_new(mrb); - if (!p) return NULL; - p->s = p->send = NULL; - p->f = f; - - mrb_parser_parse(p, c); - return p; -} -#endif - -MRB_API parser_state* -mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c) -{ - parser_state *p; - - p = mrb_parser_new(mrb); - if (!p) return NULL; - p->s = s; - p->send = s + len; - - mrb_parser_parse(p, c); - return p; -} - -MRB_API parser_state* -mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c) -{ - return mrb_parse_nstring(mrb, s, strlen(s), c); -} - -static mrb_value -load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) -{ - struct RClass *target = mrb->object_class; - struct RProc *proc; - mrb_value v; - unsigned int keep = 0; - - if (!p) { - return mrb_undef_value(); - } - 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); - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); - mrb_parser_free(p); - return mrb_undef_value(); - } - else { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error")); - mrb_parser_free(p); - return mrb_undef_value(); - } - } - proc = mrb_generate_code(mrb, p); - mrb_parser_free(p); - 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) mrb_codedump_all(mrb, proc); - if (c->no_exec) return mrb_obj_value(proc); - if (c->target_class) { - target = c->target_class; - } - if (c->keep_lv) { - keep = c->slen + 1; - } - else { - c->keep_lv = TRUE; - } - } - proc->target_class = target; - if (mrb->c->ci) { - mrb->c->ci->target_class = target; - } - v = mrb_toplevel_run_keep(mrb, proc, keep); - if (mrb->exc) return mrb_nil_value(); - return v; -} - -#ifdef ENABLE_STDIO -MRB_API mrb_value -mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c) -{ - return load_exec(mrb, mrb_parse_file(mrb, f, c), c); -} - -MRB_API mrb_value -mrb_load_file(mrb_state *mrb, FILE *f) -{ - return mrb_load_file_cxt(mrb, f, NULL); -} -#endif - -MRB_API mrb_value -mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c) -{ - return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c); -} - -MRB_API mrb_value -mrb_load_nstring(mrb_state *mrb, const char *s, int len) -{ - return mrb_load_nstring_cxt(mrb, s, len, NULL); -} - -MRB_API mrb_value -mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c) -{ - return mrb_load_nstring_cxt(mrb, s, strlen(s), c); -} - -MRB_API mrb_value -mrb_load_string(mrb_state *mrb, const char *s) -{ - return mrb_load_string_cxt(mrb, s, NULL); -} - -#ifdef ENABLE_STDIO - -static void -dump_prefix(node *tree, int offset) -{ - printf("%05d ", tree->lineno); - while (offset--) { - putc(' ', stdout); - putc(' ', stdout); - } -} - -static void -dump_recur(mrb_state *mrb, node *tree, int offset) -{ - while (tree) { - mrb_parser_dump(mrb, tree->car, offset); - tree = tree->cdr; - } -} - -#endif - -void -mrb_parser_dump(mrb_state *mrb, node *tree, int offset) -{ -#ifdef ENABLE_STDIO - int nodetype; - - if (!tree) return; - again: - dump_prefix(tree, offset); - nodetype = (int)(intptr_t)tree->car; - tree = tree->cdr; - switch (nodetype) { - case NODE_BEGIN: - printf("NODE_BEGIN:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_RESCUE: - printf("NODE_RESCUE:\n"); - if (tree->car) { - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - } - tree = tree->cdr; - if (tree->car) { - node *n2 = tree->car; - - dump_prefix(n2, offset+1); - printf("rescue:\n"); - while (n2) { - node *n3 = n2->car; - if (n3->car) { - dump_prefix(n2, offset+2); - printf("handle classes:\n"); - dump_recur(mrb, n3->car, offset+3); - } - if (n3->cdr->car) { - dump_prefix(n3, offset+2); - printf("exc_var:\n"); - mrb_parser_dump(mrb, n3->cdr->car, offset+3); - } - if (n3->cdr->cdr->car) { - dump_prefix(n3, 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(tree, offset+1); - printf("else:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - } - break; - - case NODE_ENSURE: - printf("NODE_ENSURE:\n"); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("ensure:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); - break; - - case NODE_LAMBDA: - printf("NODE_BLOCK:\n"); - goto block; - - case NODE_BLOCK: - block: - printf("NODE_BLOCK:\n"); - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, 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(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - break; - - case NODE_IF: - printf("NODE_IF:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("then:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - if (tree->cdr->cdr->car) { - dump_prefix(tree, offset+1); - printf("else:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); - } - break; - - case NODE_AND: - printf("NODE_AND:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_OR: - printf("NODE_OR:\n"); - 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) { - mrb_parser_dump(mrb, tree->car, offset+1); - } - tree = tree->cdr; - while (tree) { - dump_prefix(tree, offset+1); - printf("case:\n"); - dump_recur(mrb, tree->car->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car->cdr, offset+2); - tree = tree->cdr; - } - break; - - case NODE_WHILE: - printf("NODE_WHILE:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_UNTIL: - printf("NODE_UNTIL:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_FOR: - printf("NODE_FOR:\n"); - dump_prefix(tree, offset+1); - printf("var:\n"); - { - node *n2 = tree->car; - - if (n2->car) { - dump_prefix(n2, offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("rest:\n"); - mrb_parser_dump(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } - } - } - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("in:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("do:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - break; - - case NODE_SCOPE: - printf("NODE_SCOPE:\n"); - { - node *n2 = tree->car; - mrb_bool first_lval = TRUE; - - if (n2 && (n2->car || n2->cdr)) { - dump_prefix(n2, offset+1); - printf("local variables:\n"); - dump_prefix(n2, offset+2); - while (n2) { - if (n2->car) { - if (!first_lval) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - first_lval = FALSE; - } - n2 = n2->cdr; - } - printf("\n"); - } - } - tree = tree->cdr; - offset++; - goto again; - - case NODE_FCALL: - case NODE_CALL: - printf("NODE_CALL:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("method='%s' (%d)\n", - mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); - tree = tree->cdr->cdr->car; - if (tree) { - dump_prefix(tree, offset+1); - printf("args:\n"); - dump_recur(mrb, tree->car, offset+2); - if (tree->cdr) { - dump_prefix(tree, offset+1); - printf("block:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - } - } - break; - - case NODE_DOT2: - printf("NODE_DOT2:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_DOT3: - printf("NODE_DOT3:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_COLON2: - printf("NODE_COLON2:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); - break; - - case NODE_COLON3: - printf("NODE_COLON3:\n"); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_ARRAY: - printf("NODE_ARRAY:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_HASH: - printf("NODE_HASH:\n"); - while (tree) { - dump_prefix(tree, offset+1); - printf("key:\n"); - mrb_parser_dump(mrb, tree->car->car, offset+2); - dump_prefix(tree, offset+1); - printf("value:\n"); - mrb_parser_dump(mrb, tree->car->cdr, offset+2); - tree = tree->cdr; - } - break; - - case NODE_SPLAT: - printf("NODE_SPLAT:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_ASGN: - printf("NODE_ASGN:\n"); - dump_prefix(tree, offset+1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_MASGN: - printf("NODE_MASGN:\n"); - dump_prefix(tree, offset+1); - printf("mlhs:\n"); - { - node *n2 = tree->car; - - if (n2->car) { - dump_prefix(tree, offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("rest:\n"); - if (n2->car == (node*)-1) { - dump_prefix(n2, offset+2); - printf("(empty)\n"); - } - else { - mrb_parser_dump(mrb, n2->car, offset+3); - } - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } - } - } - dump_prefix(tree, offset+1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_OP_ASGN: - printf("NODE_OP_ASGN:\n"); - dump_prefix(tree, offset+1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); - tree = tree->cdr; - mrb_parser_dump(mrb, tree->car, offset+1); - break; - - case NODE_SUPER: - printf("NODE_SUPER:\n"); - if (tree) { - dump_prefix(tree, offset+1); - printf("args:\n"); - dump_recur(mrb, tree->car, offset+2); - if (tree->cdr) { - dump_prefix(tree, offset+1); - printf("block:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - } - } - break; - - case NODE_ZSUPER: - printf("NODE_ZSUPER\n"); - break; - - case NODE_RETURN: - printf("NODE_RETURN:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_YIELD: - printf("NODE_YIELD:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_BREAK: - printf("NODE_BREAK:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_NEXT: - printf("NODE_NEXT:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_REDO: - printf("NODE_REDO\n"); - break; - - case NODE_RETRY: - printf("NODE_RETRY\n"); - break; - - case NODE_LVAR: - printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_GVAR: - printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_IVAR: - printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_CVAR: - printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_CONST: - printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_MATCH: - printf("NODE_MATCH:\n"); - dump_prefix(tree, offset + 1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset + 2); - dump_prefix(tree, offset + 1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset + 2); - break; - - case NODE_BACK_REF: - printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); - break; - - case NODE_NTH_REF: - printf("NODE_NTH_REF: $%d\n", (int)(intptr_t)tree); - break; - - case NODE_ARG: - printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_BLOCK_ARG: - printf("NODE_BLOCK_ARG:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_INT: - printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); - break; - - case NODE_FLOAT: - printf("NODE_FLOAT %s\n", (char*)tree); - break; - - case NODE_NEGATE: - printf("NODE_NEGATE\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_STR: - printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); - break; - - case NODE_DSTR: - printf("NODE_DSTR\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_XSTR: - printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); - break; - - case NODE_DXSTR: - printf("NODE_DXSTR\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_REGX: - printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr); - break; - - case NODE_DREGX: - printf("NODE_DREGX\n"); - dump_recur(mrb, tree->car, offset+1); - dump_prefix(tree, offset); - printf("tail: %s\n", (char*)tree->cdr->cdr->car); - dump_prefix(tree, offset); - printf("opt: %s\n", (char*)tree->cdr->cdr->cdr); - break; - - case NODE_SYM: - printf("NODE_SYM :%s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_SELF: - printf("NODE_SELF\n"); - break; - - case NODE_NIL: - printf("NODE_NIL\n"); - break; - - case NODE_TRUE: - printf("NODE_TRUE\n"); - break; - - case NODE_FALSE: - printf("NODE_FALSE\n"); - break; - - case NODE_ALIAS: - printf("NODE_ALIAS %s %s:\n", - mrb_sym2name(mrb, sym(tree->car)), - mrb_sym2name(mrb, sym(tree->cdr))); - break; - - case NODE_UNDEF: - printf("NODE_UNDEF"); - { - node *t = tree; - while (t) { - printf(" %s", mrb_sym2name(mrb, sym(t->car))); - t = t->cdr; - } - } - printf(":\n"); - break; - - case NODE_CLASS: - printf("NODE_CLASS:\n"); - if (tree->car->car == (node*)0) { - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else if (tree->car->car == (node*)1) { - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else { - mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - if (tree->cdr->car) { - dump_prefix(tree, offset+1); - printf("super:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); - break; - - case NODE_MODULE: - printf("NODE_MODULE:\n"); - if (tree->car->car == (node*)0) { - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else if (tree->car->car == (node*)1) { - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else { - mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); - break; - - case NODE_SCLASS: - printf("NODE_SCLASS:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); - break; - - case NODE_DEF: - printf("NODE_DEF:\n"); - dump_prefix(tree, offset+1); - printf("%s\n", mrb_sym2name(mrb, sym(tree->car))); - tree = tree->cdr; - { - node *n2 = tree->car; - mrb_bool first_lval = TRUE; - - if (n2 && (n2->car || n2->cdr)) { - dump_prefix(n2, offset+1); - printf("local variables:\n"); - dump_prefix(n2, offset+2); - while (n2) { - if (n2->car) { - if (!first_lval) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - first_lval = FALSE; - } - n2 = n2->cdr; - } - printf("\n"); - } - } - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, 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(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } - } - mrb_parser_dump(mrb, tree->cdr->car, offset+1); - break; - - case NODE_SDEF: - printf("NODE_SDEF:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); - tree = tree->cdr->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, 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(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } - } - tree = tree->cdr; - mrb_parser_dump(mrb, tree->car, offset+1); - break; - - case NODE_POSTEXE: - printf("NODE_POSTEXE:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_HEREDOC: - printf("NODE_HEREDOC:\n"); - mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); - break; - - default: - printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); - break; - } -#endif -} diff --git a/src/print.c b/src/print.c index b43936b13..077fa4f06 100644 --- a/src/print.c +++ b/src/print.c @@ -8,49 +8,35 @@ #include "mruby/string.h" #include "mruby/variable.h" +#ifdef ENABLE_STDIO static void -printstr(mrb_state *mrb, mrb_value obj) +printstr(mrb_value obj, FILE *stream) { -#ifdef ENABLE_STDIO - char *s; - int len; - if (mrb_string_p(obj)) { - s = RSTRING_PTR(obj); - len = RSTRING_LEN(obj); - fwrite(s, len, 1, stdout); + fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stream); + putc('\n', stream); } -#endif } +#else +# define printstr(obj, stream) (void)0 +#endif MRB_API void mrb_p(mrb_state *mrb, mrb_value obj) { -#ifdef ENABLE_STDIO - mrb_value val; + mrb_value val = mrb_inspect(mrb, obj); - val = mrb_funcall(mrb, obj, "inspect", 0); - if (!mrb_string_p(val)) { - val = mrb_obj_as_string(mrb, obj); - } - printstr(mrb, val); - putc('\n', stdout); -#endif + printstr(val, stdout); } MRB_API void mrb_print_error(mrb_state *mrb) { -#ifdef ENABLE_STDIO mrb_value s; mrb_print_backtrace(mrb); s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - if (mrb_string_p(s)) { - fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr); - putc('\n', stderr); - } -#endif + printstr(s, stderr); } MRB_API void @@ -59,8 +45,7 @@ mrb_show_version(mrb_state *mrb) mrb_value msg; 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")); + printstr(msg, stdout); } MRB_API void @@ -69,6 +54,5 @@ mrb_show_copyright(mrb_state *mrb) mrb_value msg; 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")); + printstr(msg, stdout); } diff --git a/src/proc.c b/src/proc.c index 4cb9ffe18..8a2b6bbb6 100644 --- a/src/proc.c +++ b/src/proc.c @@ -93,6 +93,7 @@ mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const int i; p->env = e = env_new(mrb, argc); + mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env); MRB_ENV_UNSHARE_STACK(e); e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); if (argv) { @@ -200,7 +201,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) struct RProc *p = mrb_proc_ptr(self); mrb_code *iseq = mrb_proc_iseq(mrb, p); mrb_aspec aspec; - int ma, ra, pa, arity; + int ma, op, ra, pa, arity; if (MRB_PROC_CFUNC_P(p)) { /* TODO cfunc aspec not implemented yet */ @@ -214,9 +215,10 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) aspec = GETARG_Ax(*iseq); ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); ra = MRB_ASPEC_REST(aspec); pa = MRB_ASPEC_POST(aspec); - arity = ra ? -(ma + pa + 1) : ma + pa; + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; return mrb_fixnum_value(arity); } diff --git a/src/range.c b/src/range.c index b427dc1b7..b58b6a1c8 100644 --- a/src/range.c +++ b/src/range.c @@ -290,7 +290,7 @@ range_to_s(mrb_state *mrb, mrb_value range) str2 = mrb_obj_as_string(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); + mrb_str_cat_str(mrb, str, str2); return str; } @@ -315,7 +315,7 @@ range_inspect(mrb_state *mrb, mrb_value range) 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); + mrb_str_cat_str(mrb, str, str2); return str; } diff --git a/src/state.c b/src/state.c index 2efd34334..bfd99e4c3 100644 --- a/src/state.c +++ b/src/state.c @@ -234,6 +234,7 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c) MRB_API void mrb_close(mrb_state *mrb) { + if (!mrb) return; if (mrb->atexit_stack_len > 0) { mrb_int i; for (i = mrb->atexit_stack_len; i > 0; --i) { diff --git a/src/string.c b/src/string.c index 128578afd..e93fd4606 100644 --- a/src/string.c +++ b/src/string.c @@ -43,6 +43,69 @@ mrb_str_strlen(mrb_state *mrb, struct RString *s) return max; } +#ifdef _WIN32 +#include <windows.h> + +char* +mrb_utf8_from_locale(const char *str, size_t len) +{ + wchar_t* wcsp; + char* mbsp; + size_t mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = strlen(str); + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} + +char* +mrb_locale_from_utf8(const char *utf8, size_t len) +{ + wchar_t* wcsp; + char* mbsp; + size_t mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = strlen(utf8); + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} +#endif + static inline void resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) { @@ -75,9 +138,18 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_frozen(mrb_state *mrb, struct RString *s) +{ + if (RSTR_FROZEN_P(s)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); + } +} + MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { + check_frozen(mrb, s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -119,6 +191,15 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } +static mrb_value +mrb_str_freeze(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + + RSTR_SET_FROZEN_FLAG(s); + return str; +} + MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -1100,7 +1181,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of <i>str</i> with all uppercase letters replaced with their * lowercase counterparts. The operation is locale insensitive---only - * characters ``A'' to ``Z'' are affected. + * characters 'A' to 'Z' are affected. * * "hEllO".downcase #=> "hello" */ @@ -1345,6 +1426,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { long len; + check_frozen(mrb, s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -1703,7 +1785,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) * * If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If * <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is - * split on whitespace as if ` ' were specified. + * split on whitespace as if ' ' were specified. * * If the <i>limit</i> parameter is omitted, trailing null fields are * suppressed. If <i>limit</i> is a positive number, at most that number of @@ -1715,10 +1797,8 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) * " now's the time".split #=> ["now's", "the", "time"] * " now's the time".split(' ') #=> ["now's", "the", "time"] * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] - * "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"] * "hello".split(//) #=> ["h", "e", "l", "l", "o"] * "hello".split(//, 3) #=> ["h", "e", "llo"] - * "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"] * * "mellow yellow".split("ello") #=> ["m", "w y", "w"] * "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] @@ -1846,7 +1926,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) const char *p; char sign = 1; int c, uscore; - unsigned long n = 0; + uint64_t n = 0; mrb_int val; #define conv_digit(c) \ @@ -1929,7 +2009,7 @@ 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 */ + if (*str == '0') { /* squeeze preceding 0s */ uscore = 0; while ((c = *++str) == '0' || c == '_') { if (c == '_') { @@ -1966,9 +2046,9 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) } 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)); + 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) { @@ -1987,7 +2067,8 @@ bad: MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - struct RString *ps = mrb_str_ptr(*ptr); + mrb_value str = mrb_str_to_str(mrb, *ptr); + struct RString *ps = mrb_str_ptr(str); mrb_int len = mrb_str_strlen(mrb, ps); char *p = RSTR_PTR(ps); @@ -2004,12 +2085,12 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; - str = mrb_str_to_str(mrb, str); if (badcheck) { + /* Raises if the string contains a null character (the badcheck) */ s = mrb_string_value_cstr(mrb, &str); } else { - s = RSTRING_PTR(str); + s = mrb_string_value_ptr(mrb, str); } if (s) { len = RSTRING_LEN(str); @@ -2058,6 +2139,7 @@ MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) { char *end; + char buf[DBL_DIG * 4 + 10]; double d; enum {max_width = 20}; @@ -2078,7 +2160,6 @@ bad: return d; } if (*end) { - char buf[DBL_DIG * 4 + 10]; char *n = buf; char *e = buf + sizeof(buf) - 1; char prev = 0; @@ -2212,7 +2293,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of <i>str</i> with all lowercase letters replaced with their * uppercase counterparts. The operation is locale insensitive---only - * characters ``a'' to ``z'' are affected. + * characters 'a' to 'z' are affected. * * "hEllO".upcase #=> "HELLO" */ @@ -2367,10 +2448,10 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) } MRB_API mrb_value -mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2) +mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { str2 = mrb_str_to_str(mrb, str2); - return mrb_str_cat_str(mrb, str, str2); + return mrb_str_cat_str(mrb, str1, str2); } #define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ @@ -2515,4 +2596,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); + + mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } diff --git a/src/variable.c b/src/variable.c index 3e451df05..efe6fad12 100644 --- a/src/variable.c +++ b/src/variable.c @@ -563,7 +563,7 @@ MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) { if (!mrb_iv_p(mrb, iv_name)) { - mrb_name_error(mrb, iv_name, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } @@ -609,7 +609,7 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) else { ins = mrb_inspect(mrb, v); } - mrb_str_append(mrb, str, ins); + mrb_str_cat_str(mrb, str, ins); return 0; } diff --git a/src/version.c b/src/version.c index 7aac44d62..fc3b2fc7a 100644 --- a/src/version.c +++ b/src/version.c @@ -7,6 +7,7 @@ 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_NO", mrb_fixnum_value(MRUBY_RELEASE_NO)); 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)); @@ -266,6 +266,7 @@ ecall(mrb_state *mrb, int i) mrb_value *self = mrb->c->stack; struct RObject *exc; + if (i<0) return; p = mrb->c->ensure[i]; if (!p) return; if (mrb->c->ci->eidx > i) @@ -723,6 +724,8 @@ argnum_error(mrb_state *mrb, mrb_int num) #define CALL_MAXARGS 127 +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + MRB_API mrb_value mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { @@ -1030,7 +1033,7 @@ RETRY_TRY_BLOCK: mrb_callinfo *ci = mrb->c->ci; int n, eidx = ci->eidx; - for (n=0; n<a && eidx > ci[-1].eidx; n++) { + for (n=0; n<a && (ci == mrb->c->cibase || eidx > ci[-1].eidx); n++) { ecall(mrb, --eidx); ARENA_RESTORE(mrb, ai); } @@ -1074,9 +1077,21 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } @@ -1471,9 +1486,6 @@ RETRY_TRY_BLOCK: if (ci->ridx == 0) goto L_STOP; goto L_RESCUE; } - while (eidx > ci[-1].eidx) { - ecall(mrb, --eidx); - } while (ci[0].ridx == ci[-1].ridx) { cipop(mrb); ci = mrb->c->ci; @@ -1483,6 +1495,9 @@ RETRY_TRY_BLOCK: MRB_THROW(prev_jmp); } if (ci == mrb->c->cibase) { + while (eidx > 0) { + ecall(mrb, --eidx); + } if (ci->ridx == 0) { if (mrb->c == mrb->root_c) { regs = mrb->c->stack = mrb->c->stbase; @@ -2125,33 +2140,28 @@ RETRY_TRY_BLOCK: int pre = GETARG_B(i); int post = GETARG_C(i); + struct RArray *ary; + int len, idx; + if (!mrb_array_p(v)) { - regs[a++] = mrb_ary_new_capa(mrb, 0); + v = mrb_ary_new_from_values(mrb, 1, ®s[a]); + } + ary = mrb_ary_ptr(v); + len = ary->len; + if (len > pre + post) { + regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); while (post--) { - SET_NIL_VALUE(regs[a]); - a++; + regs[a++] = ary->ptr[len-post-1]; } } else { - struct RArray *ary = mrb_ary_ptr(v); - int len = ary->len; - int idx; - - if (len > pre + post) { - regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); - while (post--) { - regs[a++] = ary->ptr[len-post-1]; - } + regs[a++] = mrb_ary_new_capa(mrb, 0); + for (idx=0; idx+pre<len; idx++) { + regs[a+idx] = ary->ptr[pre+idx]; } - else { - regs[a++] = mrb_ary_new_capa(mrb, 0); - for (idx=0; idx+pre<len; idx++) { - regs[a+idx] = ary->ptr[pre+idx]; - } - while (idx < post) { - SET_NIL_VALUE(regs[a+idx]); - idx++; - } + while (idx < post) { + SET_NIL_VALUE(regs[a+idx]); + idx++; } } ARENA_RESTORE(mrb, ai); |
