diff options
65 files changed, 4025 insertions, 3294 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2013 mruby developers +Copyright (c) 2014 mruby developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -73,7 +73,7 @@ documentation with examples under *examples/mrbgems*. ## License -Copyright (c) 2013 mruby developers +Copyright (c) 2014 mruby developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -61,7 +61,7 @@ MRuby.each_target do |target| gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } gem_libraries = gems.map { |g| g.linker.libraries } gem_library_paths = gems.map { |g| g.linker.library_paths } - linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries, gem_flags_after_libraries end if target == MRuby.targets['host'] diff --git a/build_config.rb b/build_config.rb index 83dc01940..85d94df14 100644 --- a/build_config.rb +++ b/build_config.rb @@ -8,6 +8,8 @@ MRuby::Build.new do |conf| toolchain :gcc end + enable_debug + # Use mrbgems # conf.gem 'examples/mrbgems/ruby_extension_example' # conf.gem 'examples/mrbgems/c_extension_example' do |g| diff --git a/include/mruby.h b/include/mruby.h index e92550213..4bd6a3706 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1,7 +1,7 @@ /* ** mruby - An embeddable Ruby implementation ** -** Copyright (c) mruby developers 2010-2013 +** Copyright (c) mruby developers 2010-2014 ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the @@ -156,6 +156,7 @@ typedef struct mrb_state { #ifdef ENABLE_DEBUG void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); + void (*debug_op_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); #endif struct RClass *eException_class; @@ -239,7 +240,6 @@ mrb_value mrb_check_intern_str(mrb_state*,mrb_value); const char *mrb_sym2name(mrb_state*,mrb_sym); const char *mrb_sym2name_len(mrb_state*,mrb_sym,size_t*); mrb_value mrb_sym2str(mrb_state*,mrb_sym); -mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value); void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */ void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */ @@ -252,6 +252,7 @@ void mrb_free(mrb_state*, void*); mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); mrb_value mrb_str_new_cstr(mrb_state*, const char*); mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); +#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), sizeof(lit) - 1) mrb_state* mrb_open(void); mrb_state* mrb_open_allocf(mrb_allocf, void *ud); @@ -365,7 +366,6 @@ void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, c const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); -mrb_value mrb_block_proc(void); mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); diff --git a/include/mruby/gc.h b/include/mruby/gc.h index 7afa24b48..02714be8e 100644 --- a/include/mruby/gc.h +++ b/include/mruby/gc.h @@ -7,11 +7,16 @@ #ifndef MRUBY_GC_H #define MRUBY_GC_H -#include "mruby.h" -#include "mruby/value.h" +#if defined(__cplusplus) +extern "C" { +#endif -typedef void (each_object_callback)(mrb_state *mrb, struct RBasic* obj, void *data); -void mrb_objspace_each_objects(mrb_state *mrb, each_object_callback* callback, void *data); +typedef void (mrb_each_object_callback)(mrb_state *mrb, struct RBasic *obj, void *data); +void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data); void mrb_free_context(mrb_state *mrb, struct mrb_context *c); +#if defined(__cplusplus) +} /* extern "C" { */ +#endif + #endif /* MRUBY_GC_H */ diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 33ee99be0..6fe5c30f4 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -58,4 +58,7 @@ MRuby::GemBox.new do |conf| # Generate mruby command conf.gem :core => "mruby-bin-mruby" + + # Use mruby verison + conf.gem :core => "mruby-version" end diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 81eef7f82..75d51265b 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -8,21 +8,17 @@ #include <stdlib.h> #include <string.h> - -#include <mruby.h> +#include "mruby.h" #include "mruby/array.h" -#include <mruby/proc.h> -#include <mruby/data.h> -#include <mruby/compile.h> +#include "mruby/proc.h" +#include "mruby/compile.h" +#include "mruby/string.h" + #ifdef ENABLE_READLINE #include <limits.h> #include <readline/readline.h> #include <readline/history.h> -#endif -#include <mruby/string.h> - -#ifdef ENABLE_READLINE static const char *history_file_name = ".mirb_history"; char history_path[PATH_MAX]; #endif @@ -46,7 +42,7 @@ p(mrb_state *mrb, mrb_value obj, int prompt) /* Guess if the user might want to enter more * or if he wants an evaluation of his code now */ -mrb_bool +static mrb_bool is_code_block_open(struct mrb_parser_state *parser) { int code_block_open = FALSE; @@ -225,7 +221,7 @@ print_hint(void) } /* Print the command line prompt of the REPL */ -void +static void print_cmdline(int code_block_open) { if (code_block_open) { @@ -236,7 +232,7 @@ print_cmdline(int code_block_open) } } -void codedump_all(mrb_state*, struct RProc*); +void mrb_codedump_all(mrb_state*, struct RProc*); int main(int argc, char **argv) @@ -368,7 +364,7 @@ main(int argc, char **argv) struct RProc *proc = mrb_generate_code(mrb, parser); if (args.verbose) { - codedump_all(mrb, proc); + mrb_codedump_all(mrb, proc); } /* pass a proc for evaulation */ nregs = first_command ? 0: proc->body.irep->nregs; diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index ef0ac4978..54b2f8b65 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -1,13 +1,11 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include "mruby.h" -#include "mruby/proc.h" #include "mruby/array.h" -#include "mruby/string.h" #include "mruby/compile.h" #include "mruby/dump.h" #include "mruby/variable.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #ifndef ENABLE_STDIO static void diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 757eb235d..9e6be1471 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -218,9 +218,15 @@ static mrb_value fiber_yield(mrb_state *mrb, mrb_value self) { struct mrb_context *c = mrb->c; + mrb_callinfo *ci; mrb_value *a; int len; + for (ci = c->ci; ci >= c->cibase; ci--) { + if (ci->acc < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "can't cross C function boundary"); + } + } if (!c->prev) { mrb_raise(mrb, E_ARGUMENT_ERROR, "can't yield from root fiber"); } diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c index 94518924e..c6e72f451 100644 --- a/mrbgems/mruby-hash-ext/src/hash-ext.c +++ b/mrbgems/mruby-hash-ext/src/hash-ext.c @@ -6,11 +6,8 @@ #include "mruby.h" #include "mruby/array.h" -#include "mruby/class.h" #include "mruby/hash.h" #include "mruby/khash.h" -#include "mruby/string.h" -#include "mruby/variable.h" /* * call-seq: diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index bb6955b45..22c1668fa 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -1,6 +1,5 @@ #include <limits.h> #include "mruby.h" -#include "mruby/numeric.h" static mrb_value mrb_int_chr(mrb_state *mrb, mrb_value x) diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index ac6189ded..538959f2a 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -1,23 +1,23 @@ #include <mruby.h> #include <mruby/gc.h> #include <mruby/hash.h> -#include <mruby/value.h> struct os_count_struct { - size_t total; - size_t freed; - size_t counts[MRB_TT_MAXDEFINE+1]; + mrb_int total; + mrb_int freed; + mrb_int counts[MRB_TT_MAXDEFINE+1]; }; -void -os_count_object_type(mrb_state *mrb, struct RBasic* obj, void *data) +static void +os_count_object_type(mrb_state *mrb, struct RBasic *obj, void *data) { - struct os_count_struct* obj_count; - obj_count = (struct os_count_struct*)(data); + struct os_count_struct *obj_count; + obj_count = (struct os_count_struct*)data; if (is_dead(mrb, obj)) { obj_count->freed++; - } else { + } + else { obj_count->counts[obj->tt]++; obj_count->total++; } @@ -43,11 +43,11 @@ os_count_object_type(mrb_state *mrb, struct RBasic* obj, void *data) * */ -mrb_value +static mrb_value os_count_objects(mrb_state *mrb, mrb_value self) { - struct os_count_struct obj_count; - size_t i; + struct os_count_struct obj_count = { 0 }; + enum mrb_vtype i; mrb_value hash; if (mrb_get_args(mrb, "|H", &hash) == 0) { @@ -58,21 +58,15 @@ os_count_objects(mrb_state *mrb, mrb_value self) mrb_hash_clear(mrb, hash); } - for (i = 0; i <= MRB_TT_MAXDEFINE; i++) { - obj_count.counts[i] = 0; - } - obj_count.total = 0; - obj_count.freed = 0; - mrb_objspace_each_objects(mrb, os_count_object_type, &obj_count); - mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "TOTAL")), mrb_fixnum_value(obj_count.total)); - mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "FREE")), mrb_fixnum_value(obj_count.freed)); + mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_lit(mrb, "TOTAL")), mrb_fixnum_value(obj_count.total)); + mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_lit(mrb, "FREE")), mrb_fixnum_value(obj_count.freed)); - for (i = 0; i < MRB_TT_MAXDEFINE; i++) { + for (i = MRB_TT_FALSE; i < MRB_TT_MAXDEFINE; i++) { mrb_value type; switch (i) { -#define COUNT_TYPE(t) case (t): type = mrb_symbol_value(mrb_intern_cstr(mrb, #t)); break; +#define COUNT_TYPE(t) case (t): type = mrb_symbol_value(mrb_intern_lit(mrb, #t)); break; COUNT_TYPE(MRB_TT_FALSE); COUNT_TYPE(MRB_TT_FREE); COUNT_TYPE(MRB_TT_TRUE); @@ -107,11 +101,13 @@ os_count_objects(mrb_state *mrb, mrb_value self) } void -mrb_mruby_objectspace_gem_init(mrb_state* mrb) { +mrb_mruby_objectspace_gem_init(mrb_state *mrb) +{ struct RClass *os = mrb_define_module(mrb, "ObjectSpace"); - mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_OPT(1)); } void -mrb_mruby_objectspace_gem_final(mrb_state* mrb) { +mrb_mruby_objectspace_gem_final(mrb_state *mrb) +{ } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 87d96a865..f27356bb7 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -34,7 +34,7 @@ static mrb_value mrb_proc_inspect(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); - mrb_value str = mrb_str_new_cstr(mrb, "#<Proc:"); + mrb_value str = mrb_str_new_lit(mrb, "#<Proc:"); mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(self))); if (!MRB_PROC_CFUNC_P(p)) { diff --git a/mrbgems/mruby-random/src/mt19937ar.c b/mrbgems/mruby-random/src/mt19937ar.c index 3246909e8..41ed2c00d 100644 --- a/mrbgems/mruby-random/src/mt19937ar.c +++ b/mrbgems/mruby-random/src/mt19937ar.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stdio.h> #include "mt19937ar.h" /* Period parameters */ diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 5485f5098..6cd4de948 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -19,6 +19,7 @@ #define BITSPERDIG (sizeof(mrb_int)*CHAR_BIT) #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n))) +mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value); static void fmt_setup(char*,size_t,int,int,mrb_int,mrb_int); static char* diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 6718e734a..f194bbc0e 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -1,7 +1,7 @@ -#include "mruby.h" -#include "mruby/string.h" #include <ctype.h> #include <string.h> +#include "mruby.h" +#include "mruby/string.h" static mrb_value mrb_str_getbyte(mrb_state *mrb, mrb_value str) diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 67ed628c0..c951ea7e3 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -20,8 +20,7 @@ assert('String#dump') do end assert('String#strip') do - s = " abc " - s.strip + s = " abc " "".strip == "" and " \t\r\n\f\v".strip == "" and "\0a\0".strip == "\0a" and "abc".strip == "abc" and diff --git a/mrbgems/mruby-string-utf8/mrbgem.rake b/mrbgems/mruby-string-utf8/mrbgem.rake new file mode 100644 index 000000000..f4649be0b --- /dev/null +++ b/mrbgems/mruby-string-utf8/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-string-utf8') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' +end diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c new file mode 100644 index 000000000..2dd848c86 --- /dev/null +++ b/mrbgems/mruby-string-utf8/src/string.c @@ -0,0 +1,298 @@ +#include "mruby.h" +#include "mruby/string.h" +#include "mruby/range.h" +#include <ctype.h> +#include <string.h> + +/* TODO: duplicate definition in src/re.h */ +#define REGEXP_CLASS "Regexp" + +static const char utf8len_codepage[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1, +}; + +static size_t +utf8len(unsigned char* p) +{ + size_t len; + int i; + + if (*p == 0) + return 1; + len = utf8len_codepage[*p]; + for (i = 1; i < len; ++i) + if ((p[i] & 0xc0) != 0x80) + return 1; + return len; +} + +static size_t +mrb_utf8_strlen(mrb_value str) +{ + size_t total = 0; + unsigned char* p = (unsigned char*) RSTRING_PTR(str); + unsigned char* e = p + RSTRING_LEN(str); + while (p<e) { + p += utf8len(p); + total++; + } + return total; +} + +static mrb_value +mrb_str_size(mrb_state *mrb, mrb_value str) +{ + size_t size = mrb_utf8_strlen(str); + + return mrb_fixnum_value(size); +} + +#define RSTRING_LEN_UTF8(s) mrb_utf8_strlen(s) + +static mrb_value +noregexp(mrb_state *mrb, mrb_value self) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); + return mrb_nil_value(); +} + +static void +regexp_check(mrb_state *mrb, mrb_value obj) +{ + if (!memcmp(mrb_obj_classname(mrb, obj), REGEXP_CLASS, sizeof(REGEXP_CLASS) - 1)) { + noregexp(mrb, obj); + } +} + +static inline mrb_int +mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) +{ + const unsigned char *x = xs, *xe = xs + m; + const unsigned char *y = ys; + int i, qstable[256]; + + /* Preprocessing */ + for (i = 0; i < 256; ++i) + qstable[i] = m + 1; + for (; x < xe; ++x) + qstable[*x] = xe - x; + /* Searching */ + for (; y + m <= ys + n; y += *(qstable + y[m])) { + if (*xs == *y && memcmp(xs, y, m) == 0) + return y - ys; + } + return -1; +} +static mrb_int +mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) +{ + const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0; + + if (m > n) return -1; + else if (m == n) { + return memcmp(x0, y0, m) == 0 ? 0 : -1; + } + else if (m < 1) { + return 0; + } + else if (m == 1) { + const unsigned char *ys = y, *ye = ys + n; + for (; y < ye; ++y) { + if (*x == *y) + return y - ys; + } + return -1; + } + return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n); +} + +static mrb_value +str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + int i; + unsigned char *p = (unsigned char*) RSTRING_PTR(str), *t; + unsigned char *e = p + RSTRING_LEN(str); + + + for (i = 0; i < beg && p<e; i++) { + p += utf8len(p); + } + t = p; + for (i = 0; i < len && t<e; i++) { + t += utf8len(t); + } + return mrb_str_new(mrb, (const char*)p, (int)(t - p)); +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + mrb_value str2; + int len8 = RSTRING_LEN_UTF8(str); + + if (len < 0) return mrb_nil_value(); + if (len8 == 0) { + len = 0; + } + else if (beg < 0) { + beg = len8 + beg; + } + if (beg > len8) return mrb_nil_value(); + if (beg < 0) { + beg += len8; + if (beg < 0) return mrb_nil_value(); + } + if (beg + len > len8) + len = len8 - beg; + if (len <= 0) { + len = 0; + } + str2 = str_subseq(mrb, str, beg, len); + + return str2; +} + +static mrb_int +str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) +{ + mrb_int pos; + char *s, *sptr; + mrb_int len, slen; + + len = RSTRING_LEN(str); + slen = RSTRING_LEN(sub); + if (offset < 0) { + offset += len; + if (offset < 0) return -1; + } + if (len - offset < slen) return -1; + s = RSTRING_PTR(str); + if (offset) { + s += offset; + } + if (slen == 0) return offset; + /* need proceed one character at a time */ + sptr = RSTRING_PTR(sub); + slen = RSTRING_LEN(sub); + len = RSTRING_LEN(str) - offset; + pos = mrb_memsearch(sptr, slen, s, len); + if (pos < 0) return pos; + return pos + offset; +} + +static mrb_value +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) +{ + mrb_int idx; + + regexp_check(mrb, indx); + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + idx = mrb_fixnum(indx); + +num_index: + str = str_substr(mrb, str, idx, 1); + if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + return str; + + case MRB_TT_STRING: + if (str_index(mrb, str, indx, 0) != -1) + return mrb_str_dup(mrb, indx); + return mrb_nil_value(); + + case MRB_TT_RANGE: + /* check if indx is Range */ + { + mrb_int beg, len; + mrb_value tmp; + + len = RSTRING_LEN_UTF8(str); + if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { + tmp = str_subseq(mrb, str, beg, len); + return tmp; + } + else { + return mrb_nil_value(); + } + } + default: + idx = mrb_fixnum(indx); + goto num_index; + } + return mrb_nil_value(); /* not reached */ +} + +static mrb_value +mrb_str_aref_m(mrb_state *mrb, mrb_value str) +{ + mrb_value a1, a2; + int argc; + + argc = mrb_get_args(mrb, "o|o", &a1, &a2); + if (argc == 2) { + regexp_check(mrb, a1); + return str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2)); + } + if (argc != 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); + } + return mrb_str_aref(mrb, str, a1); +} + +static mrb_value +mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) +{ + int utf8_len = mrb_utf8_strlen(str); + if (utf8_len > 1) { + int len = RSTRING_LEN(str); + char *buf = (char *)mrb_malloc(mrb, len); + unsigned char* p = (unsigned char*)buf; + unsigned char* e = (unsigned char*)buf + len; + unsigned char* r = (unsigned char*)RSTRING_END(str); + + memcpy(buf, RSTRING_PTR(str), len); + mrb_str_modify(mrb, mrb_str_ptr(str)); + + while (p<e) { + int clen = utf8len(p); + r -= clen; + memcpy(r, p, clen); + p += clen; + } + mrb_free(mrb, buf); + } + + return str; +} + +static mrb_value +mrb_str_reverse(mrb_state *mrb, mrb_value str) +{ + return mrb_str_reverse_bang(mrb, mrb_str_dup(mrb, str)); +} + +void +mrb_mruby_string_utf8_gem_init(mrb_state* mrb) +{ + struct RClass * s = mrb->string_class; + + mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); + mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); + mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); +} + +void +mrb_mruby_string_utf8_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-string-utf8/test/string.rb b/mrbgems/mruby-string-utf8/test/string.rb new file mode 100644 index 000000000..bfa5f0170 --- /dev/null +++ b/mrbgems/mruby-string-utf8/test/string.rb @@ -0,0 +1,32 @@ +## +# String(utf8) Test + +assert('String#[]') do + assert_equal "ち", "こんにちわ世界"[3] + assert_equal nil, "こんにちわ世界"[20] + assert_equal "世", "こんにちわ世界"[-2] + assert_equal "世界", "こんにちわ世界"[-2..-1] + assert_equal "んに", "こんにちわ世界"[1,2] + assert_equal "世", "こんにちわ世界"["世"] +end + +assert('String#reverse', '15.2.10.5.29') do + a = 'こんにちわ世界!' + a.reverse + + assert_equal 'こんにちわ世界!', a + assert_equal '!界世わちにんこ', 'こんにちわ世界!'.reverse +end + +assert('String#reverse!', '15.2.10.5.30') do + a = 'こんにちわ世界!' + a.reverse! + + assert_equal '!界世わちにんこ', a + assert_equal '!界世わちにんこ', 'こんにちわ世界!'.reverse! +end + +assert('Invalid sequence') do + assert_equal 5, "\xF8\x88\x80\x80\x80".size + assert_equal 6, "\xFC\x84\x80\x80\x80\x80".size +end diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 309684422..e6d3b0796 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -10,7 +10,6 @@ #include "mruby/array.h" #include "mruby/string.h" #include "mruby/class.h" -#include "mruby/data.h" #include "mruby/variable.h" #define RSTRUCT_ARY(st) mrb_ary_ptr(st) diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index d79b30c0e..70f8a78f8 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -73,5 +73,33 @@ if Object.const_defined?(:Struct) cc = c.new(1,2) cc.select{|v| v % 2 == 0} == [2] end -end + assert('large struct') do + c = Struct.new(:m1, :m2, :m3, :m4, :m5, :m6, :m7, :m8, :m9, :m10, :m11, :m12, :m13) + cc = c.new(1,2,3,4,5,6,7,8,9,10,11,12,13) + assert_equal 1, cc.m1 + assert_equal 2, cc.m2 + assert_equal 3, cc.m3 + assert_equal 4, cc.m4 + assert_equal 5, cc.m5 + assert_equal 6, cc.m6 + assert_equal 7, cc.m7 + assert_equal 8, cc.m8 + assert_equal 9, cc.m9 + assert_equal 10, cc.m10 + assert_equal 13, cc.m13 + end + + assert('wrong struct arg count') do + c = Struct.new(:m1) + assert_raise ArgumentError do + cc = c.new(1,2,3) + end + end + + assert('struct inspect') do + c = Struct.new(:m1, :m2, :m3, :m4, :m5) + cc = c.new(1,2,3,4,5) + assert_equal "#<struct #{c.inspect} m1=1, m2=2, m3=3, m4=4, m5=5>", cc.inspect + end +end diff --git a/mrbgems/mruby-version/mrbgem.rake b/mrbgems/mruby-version/mrbgem.rake new file mode 100644 index 000000000..d7934468f --- /dev/null +++ b/mrbgems/mruby-version/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-version') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' +end diff --git a/mrbgems/mruby-version/src/version.c b/mrbgems/mruby-version/src/version.c new file mode 100644 index 000000000..ce275d509 --- /dev/null +++ b/mrbgems/mruby-version/src/version.c @@ -0,0 +1,18 @@ +#include "mruby.h" +#include "mruby/variable.h" +#include "version.h" + +void +mrb_mruby_version_gem_init(mrb_state* mrb) +{ + mrb_define_global_const(mrb, "MRUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_VERSION)); + mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE)); + mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION)); + mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT)); +} + +void +mrb_mruby_version_gem_final(mrb_state* mrb) +{ +} + diff --git a/mrbgems/mruby-version/src/version.h b/mrbgems/mruby-version/src/version.h new file mode 100644 index 000000000..69fbef0fa --- /dev/null +++ b/mrbgems/mruby-version/src/version.h @@ -0,0 +1,25 @@ +#define MRUBY_VERSION "v1.0.0" +#define MRUBY_PATCHLEVEL 0 +#define MRUBY_REVISION 0 + +#define MRUBY_RELEASE_DATE "2014-01-10" +#define MRUBY_RELEASE_YEAR 2014 +#define MRUBY_RELEASE_MONTH 1 +#define MRUBY_RELEASE_DAY 10 + +#define MRUBY_BIRTH_YEAR 2010 + +#define MRUBY_AUTHOR "mruby developers" + +#define STRINGIZE0(expr) #expr +#define STRINGIZE(expr) STRINGIZE0(expr) + +#define MRUBY_DESCRIPTION \ + "mruby "MRUBY_VERSION \ + " ("MRUBY_RELEASE_DATE") " +#define MRUBY_COPYRIGHT \ + "mruby - Copyright (c) " \ + STRINGIZE(MRUBY_BIRTH_YEAR)"-" \ + STRINGIZE(MRUBY_RELEASE_YEAR)" " \ + MRUBY_AUTHOR + diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 0593e1f04..e6aa682dd 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -395,4 +395,13 @@ module Enumerable # # ISO 15.3.2.2.20 alias to_a entries + + # redefine #hash 15.3.1.3.15 + def hash + h = 12347 + self.each do |e| + h ^= e.hash + end + h + end end diff --git a/mrblib/init_mrblib.c b/mrblib/init_mrblib.c index f65b185a3..dc902e9f9 100644 --- a/mrblib/init_mrblib.c +++ b/mrblib/init_mrblib.c @@ -1,8 +1,5 @@ #include "mruby.h" #include "mruby/irep.h" -#include "mruby/dump.h" -#include "mruby/string.h" -#include "mruby/proc.h" extern const uint8_t mrblib_irep[]; diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 8ccf3cfa8..fcfe40e3f 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -43,4 +43,11 @@ module Kernel yield end end + + # 11.4.4 Step c) + def !~(y) + !(self =~ y) + end end + +RUBY_VERSION = "1.9" diff --git a/mrblib/range.rb b/mrblib/range.rb index d43e3c223..7ea795078 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -28,6 +28,15 @@ class Range end self end + + # redefine #hash 15.3.1.3.15 + def hash + h = first.hash ^ last.hash + if self.exclude_end? + h += 1 + end + h + end end ## diff --git a/mrblib/string.rb b/mrblib/string.rb index 0d8ed4d01..19370ff82 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -135,7 +135,7 @@ class String end ## - # ISO 15.2.10.5.5 + # ISO 15.2.10.5.3 def =~(re) if re.respond_to? :to_str raise TypeError, "type mismatch: String given" diff --git a/src/array.c b/src/array.c index ec2465be1..ffb76f88e 100644 --- a/src/array.c +++ b/src/array.c @@ -4,11 +4,11 @@ ** See Copyright Notice in mruby.h */ -#include <limits.h> #include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/string.h" +#include "mruby/range.h" #include "value_array.h" #define ARY_DEFAULT_LEN 4 @@ -678,63 +678,144 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) return mrb_obj_value(b); } +static mrb_int +aget_index(mrb_state *mrb, mrb_value index) +{ + if (mrb_fixnum_p(index)) { + return mrb_fixnum(index); + } + else { + mrb_int i; + + mrb_get_args(mrb, "i", &i); + return i; + } +} + +/* + * call-seq: + * ary[index] -> obj or nil + * ary[start, length] -> new_ary or nil + * ary[range] -> new_ary or nil + * ary.slice(index) -> obj or nil + * ary.slice(start, length) -> new_ary or nil + * ary.slice(range) -> new_ary or nil + * + * Element Reference --- Returns the element at +index+, or returns a + * subarray starting at the +start+ index and continuing for +length+ + * elements, or returns a subarray specified by +range+ of indices. + * + * Negative indices count backward from the end of the array (-1 is the last + * element). For +start+ and +range+ cases the starting index is just before + * an element. Additionally, an empty array is returned when the starting + * index for an element range is at the end of the array. + * + * Returns +nil+ if the index (or starting index) are out of range. + * + * a = [ "a", "b", "c", "d", "e" ] + * a[1] => "b" + * a[1,2] => ["b", "c"] + * a[1..-2] => ["b", "c", "d"] + * + */ + mrb_value mrb_ary_aget(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int index, len; - mrb_value *argv; - int size; - - mrb_get_args(mrb, "i*", &index, &argv, &size); - switch(size) { - case 0: - return mrb_ary_ref(mrb, self, index); - - case 1: - if (!mrb_fixnum_p(argv[0])) { - mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum"); + mrb_int i, len; + mrb_value index; + + if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { + switch (mrb_type(index)) { + /* a[n..m] */ + case MRB_TT_RANGE: + if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) { + return ary_subseq(mrb, a, i, len); + } + else { + return mrb_nil_value(); + } + case MRB_TT_FIXNUM: + return mrb_ary_ref(mrb, self, mrb_fixnum(index)); + default: + return mrb_ary_ref(mrb, self, aget_index(mrb, index)); } - if (index < 0) index += a->len; - if (index < 0 || a->len < (int)index) return mrb_nil_value(); - len = mrb_fixnum(argv[0]); - if (len < 0) return mrb_nil_value(); - if (a->len == (int)index) return mrb_ary_new(mrb); - if (len > a->len - index) len = a->len - index; - return ary_subseq(mrb, a, index, len); - - default: - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - break; } - return mrb_nil_value(); /* dummy to avoid warning : not reach here */ + i = aget_index(mrb, index); + if (i < 0) i += a->len; + if (i < 0 || a->len < (int)i) return mrb_nil_value(); + if (len < 0) return mrb_nil_value(); + if (a->len == (int)i) return mrb_ary_new(mrb); + if (len > a->len - i) len = a->len - i; + + return ary_subseq(mrb, a, i, len); } +/* + * call-seq: + * ary[index] = obj -> obj + * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil + * ary[range] = obj or other_ary or nil -> obj or other_ary or nil + * + * Element Assignment --- Sets the element at +index+, or replaces a subarray + * from the +start+ index for +length+ elements, or replaces a subarray + * specified by the +range+ of indices. + * + * If indices are greater than the current capacity of the array, the array + * grows automatically. Elements are inserted into the array at +start+ if + * +length+ is zero. + * + * Negative indices will count backward from the end of the array. For + * +start+ and +range+ cases the starting index is just before an element. + * + * An IndexError is raised if a negative index points past the beginning of + * the array. + * + * See also Array#push, and Array#unshift. + * + * a = Array.new + * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] + * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] + * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] + * a[0, 2] = "?" #=> ["?", 2, nil, "4"] + * a[0..2] = "A" #=> ["A", "4"] + * a[-1] = "Z" #=> ["A", "Z"] + * a[1..-1] = nil #=> ["A", nil] + * a[1..-1] = [] #=> ["A"] + * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] + * a[3, 0] = "B" #=> [1, 2, "A", "B"] + */ + mrb_value mrb_ary_aset(mrb_state *mrb, mrb_value self) { - mrb_value *argv; - int argc; - - mrb_get_args(mrb, "*", &argv, &argc); - switch(argc) { - case 2: - if (!mrb_fixnum_p(argv[0])) { - /* Should we support Range object for 1st arg ? */ - mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum for 1st argument"); - } - mrb_ary_set(mrb, self, mrb_fixnum(argv[0]), argv[1]); - return argv[1]; - - case 3: - mrb_ary_splice(mrb, self, mrb_fixnum(argv[0]), mrb_fixnum(argv[1]), argv[2]); - return argv[2]; + mrb_value v1, v2, v3; + mrb_int i, len; - default: - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - return mrb_nil_value(); + if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { + switch (mrb_type(v1)) { + /* a[n..m] = v */ + case MRB_TT_RANGE: + if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) { + mrb_ary_splice(mrb, self, i, len, v2); + } + break; + /* a[n] = v */ + case MRB_TT_FIXNUM: + mrb_ary_set(mrb, self, mrb_fixnum(v1), v2); + break; + default: + mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); + break; + } + return v2; } + + /* a[n,m] = v */ + mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3); + return v3; } mrb_value @@ -849,6 +930,9 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) if (mrb_array_p(v)) { return v; } + if (mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) { + return mrb_funcall(mrb, v, "to_a", 0); + } else { return mrb_ary_new_from_values(mrb, 1, &v); } @@ -911,7 +995,7 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list) /* check recursive */ for(i=0; i<RARRAY_LEN(list); i++) { if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) { - return mrb_str_new(mrb, "[...]", 5); + return mrb_str_new_lit(mrb, "[...]"); } } @@ -954,7 +1038,7 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list) static mrb_value mrb_ary_inspect(mrb_state *mrb, mrb_value ary) { - if (RARRAY_LEN(ary) == 0) return mrb_str_new(mrb, "[]", 2); + if (RARRAY_LEN(ary) == 0) return mrb_str_new_lit(mrb, "[]"); return inspect_ary(mrb, ary, mrb_ary_new(mrb)); } diff --git a/src/backtrace.c b/src/backtrace.c index 25a08bb12..a221d5e5c 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -4,6 +4,7 @@ ** See Copyright Notice in mruby.h */ +#include <stdarg.h> #include "mruby.h" #include "mruby/variable.h" #include "mruby/proc.h" @@ -11,7 +12,6 @@ #include "mruby/string.h" #include "mruby/class.h" #include "mruby/debug.h" -#include <stdarg.h> typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); @@ -62,9 +62,8 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun mrb_callinfo *ci; mrb_int ciidx; const char *filename, *method, *sep; - int i, line; + int i, lineno, tracehead = 1; - func(mrb, stream, 1, "trace:\n"); ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))); if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ @@ -72,7 +71,7 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun for (i = ciidx; i >= 0; i--) { ci = &mrb->c->cibase[i]; filename = NULL; - line = -1; + lineno = -1; if (MRB_PROC_CFUNC_P(ci->proc)) { continue; @@ -91,9 +90,9 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun pc = (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))); } filename = mrb_debug_get_filename(irep, pc - irep->iseq); - line = mrb_debug_get_line(irep, pc - irep->iseq); + lineno = mrb_debug_get_line(irep, pc - irep->iseq); } - if (line == -1) continue; + if (lineno == -1) continue; if (ci->target_class == ci->proc->target_class) sep = "."; else @@ -103,29 +102,40 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun filename = "(unknown)"; } + if (tracehead) { + func(mrb, stream, 1, "trace:\n"); + tracehead = 0; + } method = mrb_sym2name(mrb, ci->mid); if (method) { const char *cn = mrb_class_name(mrb, ci->proc->target_class); if (cn) { func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, line, cn, sep, method); + func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method); func(mrb, stream, 1, "\n"); } else { func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s", filename, line, method); + func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method); func(mrb, stream, 1, "\n"); } } else { func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d", filename, line); + func(mrb, stream, 0, "%s:%d", filename, lineno); func(mrb, stream, 1, "\n"); } } } +/* mrb_print_backtrace/mrb_get_backtrace: + + function to retrieve backtrace information from the exception. + note that if you call method after the exception, call stack will be + overwritten. So invoke these functions just after detecting exceptions. +*/ + void mrb_print_backtrace(mrb_state *mrb) { diff --git a/src/class.c b/src/class.c index d29089253..4b5a014d9 100644 --- a/src/class.c +++ b/src/class.c @@ -4,9 +4,9 @@ ** See Copyright Notice in mruby.h */ -#include "mruby.h" -#include <stdarg.h> #include <ctype.h> +#include <stdarg.h> +#include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/numeric.h" @@ -866,7 +866,7 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) return result; } -mrb_value class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); +mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); /* 15.2.2.4.33 */ /* @@ -902,7 +902,7 @@ mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) struct RClass *c = mrb_class_ptr(mod); mrb_bool recur = TRUE; mrb_get_args(mrb, "|b", &recur); - return class_instance_method_list(mrb, recur, c, 0); + return mrb_class_instance_method_list(mrb, recur, c, 0); } mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c); @@ -1226,7 +1226,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); - path = mrb_str_plus(mrb, base, mrb_str_new(mrb, "::", 2)); + path = mrb_str_plus(mrb, base, mrb_str_new_lit(mrb, "::")); name = mrb_sym2name_len(mrb, sym, &len); mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len)); } @@ -1253,7 +1253,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) { - path = mrb_str_new(mrb, "#<Class:", 8); + path = mrb_str_new_lit(mrb, "#<Class:"); mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); mrb_str_cat(mrb, path, ">", 1); } @@ -1378,7 +1378,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); - str = mrb_str_new(mrb, "#<Class:", 8); + str = mrb_str_new_lit(mrb, "#<Class:"); switch (mrb_type(v)) { case MRB_TT_CLASS: diff --git a/src/codegen.c b/src/codegen.c index d0ec12bac..80cdb6ef1 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -26,7 +26,7 @@ enum looptype { LOOP_FOR, LOOP_BEGIN, LOOP_RESCUE, -} type; +}; struct loopinfo { enum looptype type; @@ -1386,7 +1386,12 @@ codegen(codegen_scope *s, node *tree, int val) if (head) { genop(s, MKOP_AB(OP_MOVE, cursp(), head)); pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + if ((intptr_t)n->car->car == NODE_SPLAT) { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + } } else { pop(); @@ -2729,7 +2734,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) break; case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c), GETARG_c(c)); + printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c)); break; case OP_RANGE: printf("OP_RANGE\tR%d\tR%d\t%d\n", GETARG_A(c), GETARG_B(c), GETARG_C(c)); @@ -2840,7 +2845,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); break; case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)\n", GETARG_A(c), GETARG_Bx(c)); + printf("OP_EXEC\tR%d\tI(%+d)\n", GETARG_A(c), GETARG_Bx(c)+1); break; case OP_SCLASS: printf("OP_SCLASS\tR%d\tR%d\n", GETARG_A(c), GETARG_B(c)); @@ -2849,10 +2854,14 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_TCLASS\tR%d\n", GETARG_A(c)); break; case OP_ERR: - printf("OP_ERR\tL(%d)\n", GETARG_Bx(c)); + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); + printf("OP_ERR\t%s\n", RSTRING_PTR(s)); + } break; case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)); + printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); break; case OP_ONERR: printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); @@ -2893,7 +2902,7 @@ codedump_recur(mrb_state *mrb, mrb_irep *irep) } void -codedump_all(mrb_state *mrb, struct RProc *proc) +mrb_codedump_all(mrb_state *mrb, struct RProc *proc) { codedump_recur(mrb, proc->body.irep); } diff --git a/src/dump.c b/src/dump.c index f1fc56d8e..37cafb134 100644 --- a/src/dump.c +++ b/src/dump.c @@ -4,10 +4,9 @@ ** See Copyright Notice in mruby.h */ +#include <ctype.h> #include <string.h> #include "mruby/dump.h" -#include <ctype.h> - #include "mruby/string.h" #include "mruby/irep.h" #include "mruby/numeric.h" @@ -595,6 +594,9 @@ write_filename_table(mrb_state *mrb, mrb_irep *irep, uint8_t **cp, mrb_sym **fp, size += sizeof(uint16_t) + fn_len; } + for (file_i=0; file_i<irep->rlen; file_i++) { + size += write_filename_table(mrb, irep->reps[file_i], &cur, fp, lp); + } *cp = cur; return size; } @@ -606,7 +608,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur) const uint8_t *bin = cur; struct rite_section_debug_header *header; mrb_sym *filenames; - size_t filenames_len = 0, i; + size_t filenames_len = 0; uint8_t *filenames_len_out; uint32_t dlen; @@ -624,9 +626,6 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur) cur += sizeof(uint16_t); section_size += sizeof(uint16_t); section_size += write_filename_table(mrb, irep, &cur, &filenames, &filenames_len); - for (i=0; i<irep->rlen; i++) { - section_size += write_filename_table(mrb, irep->reps[i], &cur, &filenames, &filenames_len); - } uint16_to_bin(filenames_len, filenames_len_out); // debug records diff --git a/src/error.c b/src/error.c index ced50e3e1..c18f492e1 100644 --- a/src/error.c +++ b/src/error.c @@ -7,10 +7,8 @@ #include <errno.h> #include <stdarg.h> #include <stdlib.h> -#include <string.h> #include "mruby.h" #include "mruby/array.h" -#include "mruby/class.h" #include "mruby/irep.h" #include "mruby/proc.h" #include "mruby/string.h" @@ -347,20 +345,13 @@ mrb_bug(mrb_state *mrb, const char *fmt, ...) exit(EXIT_FAILURE); } -int -sysexit_status(mrb_state *mrb, mrb_value err) -{ - mrb_value st = mrb_iv_get(mrb, err, mrb_intern_lit(mrb, "status")); - return mrb_fixnum(st); -} - static void set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) { mrb_funcall(mrb, info, "set_backtrace", 1, bt); } -mrb_value +static mrb_value make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr) { mrb_value mesg; diff --git a/src/error.h b/src/error.h index 4d120e989..b04dc1082 100644 --- a/src/error.h +++ b/src/error.h @@ -8,9 +8,7 @@ #define MRUBY_ERROR_H void mrb_sys_fail(mrb_state *mrb, const char *mesg); -int sysexit_status(mrb_state *mrb, mrb_value err); mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); -mrb_value make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr); mrb_value mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv); mrb_value mrb_format(mrb_state *mrb, const char *format, ...); void mrb_exc_print(mrb_state *mrb, struct RObject *exc); @@ -6,8 +6,6 @@ #include "mruby.h" #include "mruby/string.h" -#include "error.h" -#include "mruby/numeric.h" #include "mruby/data.h" #include "mruby/class.h" @@ -18,7 +16,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass); data->data = ptr; - data->type = (mrb_data_type*) type; + data->type = type; return data; } @@ -64,34 +62,6 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) return DATA_PTR(obj); } -mrb_value -mrb_lastline_get(mrb_state *mrb) -{ - mrb_value *argv; - int argc; - - mrb_get_args(mrb, "*", &argv, &argc); - if (argc < 1) { - return mrb_nil_value(); - } - else - { - return argv[0]; - } -} - -/* ------------------------------------------------ */ -/* - * Calls func(obj, arg, recursive), where recursive is non-zero if the - * current method is called recursively on obj - */ - -mrb_value -mrb_exec_recursive(mrb_state *mrb, mrb_value (*func) (mrb_state *, mrb_value, mrb_value, int), mrb_value obj, void *arg) -{ - return func(mrb, obj, *(mrb_value*)arg, 0); -} - mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { @@ -111,24 +81,11 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) name = mrb_str_intern(mrb, name); /* fall through */ case MRB_TT_SYMBOL: - return mrb_symbol(name); + id = mrb_symbol(name); } return id; } -/* - * call-seq: - * proc { |...| block } -> a_proc - * - * Equivalent to <code>Proc.new</code>. - */ - -mrb_value -mrb_block_proc(void) -{ - return mrb_nil_value(); -} - static mrb_int float_id(mrb_float f) { @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <limits.h> #include <string.h> #include <stdlib.h> #include "mruby.h" @@ -1282,21 +1281,21 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self) } void -mrb_objspace_each_objects(mrb_state *mrb, each_object_callback* callback, void *data) +mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data) { - struct heap_page* page = mrb->heaps; + struct heap_page* page = mrb->heaps; - while (page != NULL) { - RVALUE *p, *pend; + while (page != NULL) { + RVALUE *p, *pend; - p = page->objects; - pend = p + MRB_HEAP_PAGE_SIZE; - for (;p < pend; p++) { - (*callback)(mrb, &p->as.basic, data); - } - - page = page->next; + p = page->objects; + pend = p + MRB_HEAP_PAGE_SIZE; + for (;p < pend; p++) { + (*callback)(mrb, &p->as.basic, data); } + + page = page->next; + } } #ifdef GC_TEST @@ -1339,7 +1338,7 @@ test_mrb_field_write_barrier(void) puts("test_mrb_field_write_barrier"); mrb->is_generational_gc_mode = FALSE; obj = mrb_basic_ptr(mrb_ary_new(mrb)); - value = mrb_basic_ptr(mrb_str_new_cstr(mrb, "value")); + value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value")); paint_black(obj); paint_partial_white(mrb,value); @@ -1381,7 +1380,7 @@ test_mrb_field_write_barrier(void) { puts("test_mrb_field_write_barrier_value"); obj = mrb_basic_ptr(mrb_ary_new(mrb)); - mrb_value value = mrb_str_new_cstr(mrb, "value"); + mrb_value value = mrb_str_new_lit(mrb, "value"); paint_black(obj); paint_partial_white(mrb, mrb_basic_ptr(value)); @@ -1430,12 +1429,12 @@ test_add_gray_list(void) puts("test_add_gray_list"); change_gen_gc_mode(mrb, FALSE); mrb_assert(mrb->gray_list == NULL); - obj1 = mrb_basic_ptr(mrb_str_new_cstr(mrb, "test")); + obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test")); add_gray_list(mrb, obj1); mrb_assert(mrb->gray_list == obj1); mrb_assert(is_gray(obj1)); - obj2 = mrb_basic_ptr(mrb_str_new_cstr(mrb, "test")); + obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test")); add_gray_list(mrb, obj2); mrb_assert(mrb->gray_list == obj2); mrb_assert(mrb->gray_list->gcnext == obj1); @@ -1463,7 +1462,7 @@ test_gc_gray_mark(void) puts(" in MRB_TT_ARRAY"); obj_v = mrb_ary_new(mrb); - value_v = mrb_str_new_cstr(mrb, "test"); + value_v = mrb_str_new_lit(mrb, "test"); paint_gray(mrb_basic_ptr(obj_v)); paint_partial_white(mrb, mrb_basic_ptr(value_v)); mrb_ary_push(mrb, obj_v, value_v); diff --git a/src/hash.c b/src/hash.c index d1e2aa538..3bfffc0f7 100644 --- a/src/hash.c +++ b/src/hash.c @@ -788,9 +788,9 @@ inspect_hash(mrb_state *mrb, mrb_value hash, int recur) khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; - if (recur) return mrb_str_new(mrb, "{...}", 5); + if (recur) return mrb_str_new_lit(mrb, "{...}"); - str = mrb_str_new(mrb, "{", 1); + str = mrb_str_new_lit(mrb, "{"); if (h && kh_size(h) > 0) { for (k = kh_begin(h); k != kh_end(h); k++) { int ai; @@ -833,7 +833,7 @@ mrb_hash_inspect(mrb_state *mrb, mrb_value hash) khash_t(ht) *h = RHASH_TBL(hash); if (!h || kh_size(h) == 0) - return mrb_str_new(mrb, "{}", 2); + return mrb_str_new_lit(mrb, "{}"); return inspect_hash(mrb, hash, 0); } diff --git a/src/kernel.c b/src/kernel.c index 15567a65f..b17977052 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -294,12 +294,22 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) } static void +copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) +{ + struct RClass *dc = mrb_class_ptr(dst); + struct RClass *sc = mrb_class_ptr(src); + dc->mt = kh_copy(mt, mrb, sc->mt); + dc->super = sc->super; +} + +static void init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) { - switch (mrb_type(obj)) { - case MRB_TT_OBJECT: + switch (mrb_type(obj)) { case MRB_TT_CLASS: case MRB_TT_MODULE: + copy_class(mrb, dest, obj); + case MRB_TT_OBJECT: case MRB_TT_SCLASS: case MRB_TT_HASH: case MRB_TT_DATA: @@ -739,7 +749,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) } mrb_value -class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) +mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) { khint_t i; mrb_value ary; @@ -806,7 +816,7 @@ mrb_value mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag) { if (recur) - return class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); + return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); else return mrb_obj_singleton_methods(mrb, recur, obj); } @@ -1009,7 +1019,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) * If the method is not defined, <code>respond_to_missing?</code> * method is called and the result is returned. */ -mrb_value +static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { mrb_value *argv; @@ -1098,6 +1108,23 @@ mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) return mrb_obj_singleton_methods(mrb, recur, self); } +static mrb_value +mrb_obj_ceqq(mrb_state *mrb, mrb_value self) +{ + mrb_value v; + mrb_int i, len; + mrb_sym eqq = mrb_intern_lit(mrb, "==="); + mrb_value ary = mrb_ary_splat(mrb, self); + + mrb_get_args(mrb, "o", &v); + len = RARRAY_LEN(ary); + for (i=0; i<len; i++) { + mrb_value c = mrb_funcall_argv(mrb, mrb_ary_entry(ary, i), eqq, 1, &v); + if (mrb_test(c)) return mrb_true_value(); + } + return mrb_false_value(); +} + void mrb_init_kernel(mrb_state *mrb) { @@ -1149,6 +1176,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ + mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); diff --git a/src/numeric.c b/src/numeric.c index 75f5313e7..709a8e1e3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -118,14 +118,14 @@ mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit) n = mrb_float(flo); if (isnan(n)) { - result = mrb_str_new(mrb, "NaN", 3); + result = mrb_str_new_lit(mrb, "NaN"); } else if (isinf(n)) { if (n < 0) { - result = mrb_str_new(mrb, "-inf", 4); + result = mrb_str_new_lit(mrb, "-inf"); } else { - result = mrb_str_new(mrb, "inf", 3); + result = mrb_str_new_lit(mrb, "inf"); } } else { @@ -612,6 +612,12 @@ flo_truncate(mrb_state *mrb, mrb_value num) return mrb_fixnum_value((mrb_int)f); } +static mrb_value +flo_nan_p(mrb_state *mrb, mrb_value num) +{ + return mrb_bool_value(isnan(mrb_float(num))); +} + /* * Document-class: Integer * @@ -1331,4 +1337,5 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */ mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE()); } diff --git a/src/object.c b/src/object.c index daa76a03f..18524e958 100644 --- a/src/object.c +++ b/src/object.c @@ -5,11 +5,9 @@ */ #include "mruby.h" -#include "mruby/array.h" #include "mruby/class.h" #include "mruby/numeric.h" #include "mruby/string.h" -#include "error.h" mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) @@ -88,7 +86,7 @@ nil_to_s(mrb_state *mrb, mrb_value obj) static mrb_value nil_inspect(mrb_state *mrb, mrb_value obj) { - return mrb_str_new(mrb, "nil", 3); + return mrb_str_new_lit(mrb, "nil"); } /*********************************************************************** @@ -149,7 +147,7 @@ true_xor(mrb_state *mrb, mrb_value obj) static mrb_value true_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new(mrb, "true", 4); + return mrb_str_new_lit(mrb, "true"); } /* 15.2.5.3.4 */ @@ -256,7 +254,7 @@ false_or(mrb_state *mrb, mrb_value obj) static mrb_value false_to_s(mrb_state *mrb, mrb_value obj) { - return mrb_str_new(mrb, "false", 5); + return mrb_str_new_lit(mrb, "false"); } void diff --git a/src/parse.y b/src/parse.y index 106076911..163c3ea55 100644 --- a/src/parse.y +++ b/src/parse.y @@ -32,6 +32,7 @@ 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); @@ -62,6 +63,8 @@ typedef unsigned int stack_type; #define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack) #define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) +#define SET_LINENO(c,n) ((c)->lineno = (n)) + #define sym(x) ((mrb_sym)(intptr_t)(x)) #define nsym(x) ((node*)(intptr_t)(x)) @@ -906,7 +909,7 @@ end_strterm(parser_state *p) p->lex_strterm = NULL; } -parser_heredoc_info * +static parser_heredoc_info * parsing_heredoc_inf(parser_state *p) { node *nd = p->parsing_heredoc; @@ -929,7 +932,7 @@ heredoc_treat_nextline(parser_state *p) n = p->all_heredocs; if (n) { while (n->cdr) - n = n->cdr; + n = n->cdr; n->cdr = p->parsing_heredoc; } else { p->all_heredocs = p->parsing_heredoc; @@ -947,8 +950,8 @@ heredoc_treat_nextline(parser_state *p) p->parsing_heredoc = p->heredocs_from_nextline; } else { while (n->cdr != p->parsing_heredoc) { - n = n->cdr; - mrb_assert(n != NULL); + n = n->cdr; + mrb_assert(n != NULL); } m->cdr = n->cdr; n->cdr = p->heredocs_from_nextline; @@ -993,54 +996,54 @@ heredoc_end(parser_state *p) } %token - keyword_class - keyword_module - keyword_def - keyword_undef - keyword_begin - keyword_rescue - keyword_ensure - keyword_end - keyword_if - keyword_unless - keyword_then - keyword_elsif - keyword_else - keyword_case - keyword_when - keyword_while - keyword_until - keyword_for - keyword_break - keyword_next - keyword_redo - keyword_retry - keyword_in - keyword_do - keyword_do_cond - keyword_do_block - keyword_do_LAMBDA - keyword_return - keyword_yield - keyword_super - keyword_self - keyword_nil - keyword_true - keyword_false - keyword_and - keyword_or - keyword_not - modifier_if - modifier_unless - modifier_while - modifier_until - modifier_rescue - keyword_alias - keyword_BEGIN - keyword_END - keyword__LINE__ - keyword__FILE__ - keyword__ENCODING__ + keyword_class + keyword_module + keyword_def + keyword_undef + keyword_begin + keyword_rescue + keyword_ensure + keyword_end + keyword_if + keyword_unless + keyword_then + keyword_elsif + keyword_else + keyword_case + keyword_when + keyword_while + keyword_until + keyword_for + keyword_break + keyword_next + keyword_redo + keyword_retry + keyword_in + keyword_do + keyword_do_cond + keyword_do_block + keyword_do_LAMBDA + keyword_return + keyword_yield + keyword_super + keyword_self + keyword_nil + keyword_true + keyword_false + keyword_and + keyword_or + keyword_not + modifier_if + modifier_unless + modifier_while + modifier_until + modifier_rescue + keyword_alias + keyword_BEGIN + keyword_END + keyword__LINE__ + keyword__FILE__ + keyword__ENCODING__ %token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL %token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP @@ -1103,7 +1106,7 @@ heredoc_end(parser_state *p) %token <nd> tHD_STRING_PART tHD_STRING_MID /* - * precedence table + * precedence table */ %nonassoc tLOWEST @@ -1143,2063 +1146,2082 @@ heredoc_end(parser_state *p) %token tLAST_TOKEN %% -program : { - p->lstate = EXPR_BEG; - if (!p->locals) p->locals = cons(0,0); - } - top_compstmt - { - p->tree = new_scope(p, $2); - } - ; - -top_compstmt : top_stmts opt_terms - { - $$ = $1; - } - ; - -top_stmts : none - { - $$ = new_begin(p, 0); - } - | top_stmt - { - $$ = new_begin(p, $1); - } - | top_stmts terms top_stmt - { - $$ = push($1, newline_node($3)); - } - | error top_stmt - { - $$ = new_begin(p, 0); - } - ; - -top_stmt : stmt - | keyword_BEGIN - { - $<nd>$ = local_switch(p); - } - '{' top_compstmt '}' - { - yyerror(p, "BEGIN not supported"); - local_resume(p, $<nd>2); - $$ = 0; - } - ; - -bodystmt : compstmt - opt_rescue - opt_else - opt_ensure - { - if ($2) { - $$ = new_rescue(p, $1, $2, $3); - } - else if ($3) { - yywarn(p, "else without rescue is useless"); - $$ = push($1, $3); - } - else { - $$ = $1; - } - if ($4) { - if ($$) { - $$ = new_ensure(p, $$, $4); - } - else { - $$ = push($4, new_nil(p)); - } - } - } - ; - -compstmt : stmts opt_terms - { - $$ = $1; - } - ; - -stmts : none - { - $$ = new_begin(p, 0); - } - | stmt - { - $$ = new_begin(p, $1); - } - | stmts terms stmt - { - $$ = push($1, newline_node($3)); - } - | error stmt - { - $$ = new_begin(p, $2); - } - ; - -stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym - { - $$ = new_alias(p, $2, $4); - } - | keyword_undef undef_list - { - $$ = $2; - } - | stmt modifier_if expr_value - { - $$ = new_if(p, cond($3), $1, 0); - } - | stmt modifier_unless expr_value - { - $$ = new_unless(p, cond($3), $1, 0); - } - | stmt modifier_while expr_value - { - $$ = new_while(p, cond($3), $1); - } - | stmt modifier_until expr_value - { - $$ = new_until(p, cond($3), $1); - } - | stmt modifier_rescue stmt - { - $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); - } - | keyword_END '{' compstmt '}' - { - yyerror(p, "END not suported"); - $$ = new_postexe(p, $3); - } - | command_asgn - | mlhs '=' command_call - { - $$ = new_masgn(p, $1, $3); - } - | var_lhs tOP_ASGN command_call - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call - { - yyerror(p, "constant re-assignment"); - $$ = 0; - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | backref tOP_ASGN command_call - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | lhs '=' mrhs - { - $$ = new_asgn(p, $1, new_array(p, $3)); - } - | mlhs '=' arg_value - { - $$ = new_masgn(p, $1, $3); - } - | mlhs '=' mrhs - { - $$ = new_masgn(p, $1, new_array(p, $3)); - } - | expr - ; - -command_asgn : lhs '=' command_call - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' command_asgn - { - $$ = new_asgn(p, $1, $3); - } - ; - - -expr : command_call - | expr keyword_and expr - { - $$ = new_and(p, $1, $3); - } - | expr keyword_or expr - { - $$ = new_or(p, $1, $3); - } - | keyword_not opt_nl expr - { - $$ = call_uni_op(p, cond($3), "!"); - } - | '!' command_call - { - $$ = call_uni_op(p, cond($2), "!"); - } - | arg - ; - -expr_value : expr - { - if (!$1) $$ = new_nil(p); - else $$ = $1; - } - ; - -command_call : command - | block_command - ; - -block_command : block_call - | block_call dot_or_colon operation2 command_args - ; - -cmd_brace_block : tLBRACE_ARG - { - local_nest(p); - } - opt_block_param - compstmt - '}' - { - $$ = new_block(p, $3, $4); - local_unnest(p); - } - ; - -command : operation command_args %prec tLOWEST - { - $$ = new_fcall(p, $1, $2); - } - | operation command_args cmd_brace_block - { - args_with_block(p, $2, $3); - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value '.' operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | keyword_super command_args - { - $$ = new_super(p, $2); - } - | keyword_yield command_args - { - $$ = new_yield(p, $2); - } - | keyword_return call_args - { - $$ = new_return(p, ret_args(p, $2)); - } - | keyword_break call_args - { - $$ = new_break(p, ret_args(p, $2)); - } - | keyword_next call_args - { - $$ = new_next(p, ret_args(p, $2)); - } - ; - -mlhs : mlhs_basic - { - $$ = $1; - } - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -mlhs_inner : mlhs_basic - | tLPAREN mlhs_inner rparen - { - $$ = list1($2); - } - ; - -mlhs_basic : mlhs_list - { - $$ = list1($1); - } - | mlhs_list mlhs_item - { - $$ = list1(push($1,$2)); - } - | mlhs_list tSTAR mlhs_node - { - $$ = list2($1, $3); - } - | mlhs_list tSTAR mlhs_node ',' mlhs_post - { - $$ = list3($1, $3, $5); - } - | mlhs_list tSTAR - { - $$ = list2($1, new_nil(p)); - } - | mlhs_list tSTAR ',' mlhs_post - { - $$ = list3($1, new_nil(p), $4); - } - | tSTAR mlhs_node - { - $$ = list2(0, $2); - } - | tSTAR mlhs_node ',' mlhs_post - { - $$ = list3(0, $2, $4); - } - | tSTAR - { - $$ = list2(0, new_nil(p)); - } - | tSTAR ',' mlhs_post - { - $$ = list3(0, new_nil(p), $3); - } - ; - -mlhs_item : mlhs_node - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -mlhs_list : mlhs_item ',' - { - $$ = list1($1); - } - | mlhs_list mlhs_item ',' - { - $$ = push($1, $2); - } - ; - -mlhs_post : mlhs_item - { - $$ = list1($1); - } - | mlhs_list mlhs_item - { - $$ = push($1, $2); - } - ; - -mlhs_node : variable - { - assignable(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -lhs : variable - { - assignable(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -cname : tIDENTIFIER - { - yyerror(p, "class/module name must be CONSTANT"); - } - | tCONSTANT - ; - -cpath : tCOLON3 cname - { - $$ = cons((node*)1, nsym($2)); - } - | cname - { - $$ = cons((node*)0, nsym($1)); - } - | primary_value tCOLON2 cname - { - $$ = cons($1, nsym($3)); - } - ; - -fname : tIDENTIFIER - | tCONSTANT - | tFID - | op - { - p->lstate = EXPR_ENDFN; - $$ = $1; - } - | reswords - { - p->lstate = EXPR_ENDFN; - $$ = $<id>1; - } - ; - -fsym : fname - | basic_symbol - ; - -undef_list : fsym - { - $$ = new_undef(p, $1); - } - | undef_list ',' {p->lstate = EXPR_FNAME;} fsym - { - $$ = push($1, nsym($4)); - } - ; - -op : '|' { $$ = intern_c('|'); } - | '^' { $$ = intern_c('^'); } - | '&' { $$ = intern_c('&'); } - | tCMP { $$ = intern("<=>",3); } - | tEQ { $$ = intern("==",2); } - | tEQQ { $$ = intern("===",3); } - | tMATCH { $$ = intern("=~",2); } - | tNMATCH { $$ = intern("!~",2); } - | '>' { $$ = intern_c('>'); } - | tGEQ { $$ = intern(">=",2); } - | '<' { $$ = intern_c('<'); } - | tLEQ { $$ = intern("<=",2); } - | tNEQ { $$ = intern("!=",2); } - | tLSHFT { $$ = intern("<<",2); } - | tRSHFT { $$ = intern(">>",2); } - | '+' { $$ = intern_c('+'); } - | '-' { $$ = intern_c('-'); } - | '*' { $$ = intern_c('*'); } - | tSTAR { $$ = intern_c('*'); } - | '/' { $$ = intern_c('/'); } - | '%' { $$ = intern_c('%'); } - | tPOW { $$ = intern("**",2); } - | '!' { $$ = intern_c('!'); } - | '~' { $$ = intern_c('~'); } - | tUPLUS { $$ = intern("+@",2); } - | tUMINUS { $$ = intern("-@",2); } - | tAREF { $$ = intern("[]",2); } - | tASET { $$ = intern("[]=",3); } - | '`' { $$ = intern_c('`'); } - ; - -reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ - | keyword_BEGIN | keyword_END - | keyword_alias | keyword_and | keyword_begin - | keyword_break | keyword_case | keyword_class | keyword_def - | keyword_do | keyword_else | keyword_elsif - | keyword_end | keyword_ensure | keyword_false - | keyword_for | keyword_in | keyword_module | keyword_next - | keyword_nil | keyword_not | keyword_or | keyword_redo - | keyword_rescue | keyword_retry | keyword_return | keyword_self - | keyword_super | keyword_then | keyword_true | keyword_undef - | keyword_when | keyword_yield | keyword_if | keyword_unless - | keyword_while | keyword_until - ; - -arg : lhs '=' arg - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' arg modifier_rescue arg - { - $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | var_lhs tOP_ASGN arg - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | var_lhs tOP_ASGN arg modifier_rescue arg - { - $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | tCOLON3 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | backref tOP_ASGN arg - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | arg tDOT2 arg - { - $$ = new_dot2(p, $1, $3); - } - | arg tDOT3 arg - { - $$ = new_dot3(p, $1, $3); - } - | arg '+' arg - { - $$ = call_bin_op(p, $1, "+", $3); - } - | arg '-' arg - { - $$ = call_bin_op(p, $1, "-", $3); - } - | arg '*' arg - { - $$ = call_bin_op(p, $1, "*", $3); - } - | arg '/' arg - { - $$ = call_bin_op(p, $1, "/", $3); - } - | arg '%' arg - { - $$ = call_bin_op(p, $1, "%", $3); - } - | arg tPOW arg - { - $$ = call_bin_op(p, $1, "**", $3); - } - | tUMINUS_NUM tINTEGER tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUMINUS_NUM tFLOAT tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUPLUS arg - { - $$ = call_uni_op(p, $2, "+@"); - } - | tUMINUS arg - { - $$ = call_uni_op(p, $2, "-@"); - } - | arg '|' arg - { - $$ = call_bin_op(p, $1, "|", $3); - } - | arg '^' arg - { - $$ = call_bin_op(p, $1, "^", $3); - } - | arg '&' arg - { - $$ = call_bin_op(p, $1, "&", $3); - } - | arg tCMP arg - { - $$ = call_bin_op(p, $1, "<=>", $3); - } - | arg '>' arg - { - $$ = call_bin_op(p, $1, ">", $3); - } - | arg tGEQ arg - { - $$ = call_bin_op(p, $1, ">=", $3); - } - | arg '<' arg - { - $$ = call_bin_op(p, $1, "<", $3); - } - | arg tLEQ arg - { - $$ = call_bin_op(p, $1, "<=", $3); - } - | arg tEQ arg - { - $$ = call_bin_op(p, $1, "==", $3); - } - | arg tEQQ arg - { - $$ = call_bin_op(p, $1, "===", $3); - } - | arg tNEQ arg - { - $$ = call_bin_op(p, $1, "!=", $3); - } - | arg tMATCH arg - { - $$ = call_bin_op(p, $1, "=~", $3); - } - | arg tNMATCH arg - { - $$ = call_bin_op(p, $1, "!~", $3); - } - | '!' arg - { - $$ = call_uni_op(p, cond($2), "!"); - } - | '~' arg - { - $$ = call_uni_op(p, cond($2), "~"); - } - | arg tLSHFT arg - { - $$ = call_bin_op(p, $1, "<<", $3); - } - | arg tRSHFT arg - { - $$ = call_bin_op(p, $1, ">>", $3); - } - | arg tANDOP arg - { - $$ = new_and(p, $1, $3); - } - | arg tOROP arg - { - $$ = new_or(p, $1, $3); - } - | arg '?' arg opt_nl ':' arg - { - $$ = new_if(p, cond($1), $3, $6); - } - | primary - { - $$ = $1; - } - ; - -arg_value : arg - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -aref_args : none - | args trailer - { - $$ = $1; - } - | args ',' assocs trailer - { - $$ = push($1, new_hash(p, $3)); - } - | assocs trailer - { - $$ = cons(new_hash(p, $1), 0); - } - ; - -paren_args : '(' opt_call_args rparen - { - $$ = $2; - } - ; - -opt_paren_args : none - | paren_args - ; - -opt_call_args : none - | call_args - | args ',' - { - $$ = cons($1,0); - } - | args ',' assocs ',' - { - $$ = cons(push($1, new_hash(p, $3)), 0); - } - | assocs ',' - { - $$ = cons(list1(new_hash(p, $1)), 0); - } - ; - -call_args : command - { - $$ = cons(list1($1), 0); - } - | args opt_block_arg - { - $$ = cons($1, $2); - } - | assocs opt_block_arg - { - $$ = cons(list1(new_hash(p, $1)), $2); - } - | args ',' assocs opt_block_arg - { - $$ = cons(push($1, new_hash(p, $3)), $4); - } - | block_arg - { - $$ = cons(0, $1); - } - ; - -command_args : { - $<stack>$ = p->cmdarg_stack; - CMDARG_PUSH(1); - } - call_args - { - p->cmdarg_stack = $<stack>1; - $$ = $2; - } - ; - -block_arg : tAMPER arg_value - { - $$ = new_block_arg(p, $2); - } - ; - -opt_block_arg : ',' block_arg - { - $$ = $2; - } - | none - { - $$ = 0; - } - ; - -args : arg_value - { - $$ = cons($1, 0); - } - | tSTAR arg_value - { - $$ = cons(new_splat(p, $2), 0); - } - | args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - | args ',' heredoc_bodies arg_value - { - $$ = push($1, $4); - } - | args ',' heredoc_bodies tSTAR arg_value - { - $$ = push($1, new_splat(p, $5)); - } - ; - -mrhs : args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - | tSTAR arg_value - { - $$ = list1(new_splat(p, $2)); - } - ; - -primary : literal - | string - | xstring - | regexp - | heredoc - | var_ref - | backref - | tFID - { - $$ = new_fcall(p, $1, 0); - } - | keyword_begin - { - $<stack>1 = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - bodystmt - keyword_end - { - p->cmdarg_stack = $<stack>1; - $$ = $3; - } - | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen - { - $$ = $2; - } - | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen - { - $$ = 0; - } - | tLPAREN compstmt ')' - { - $$ = $2; - } - | primary_value tCOLON2 tCONSTANT - { - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - $$ = new_colon3(p, $2); - } - | tLBRACK aref_args ']' - { - $$ = new_array(p, $2); - } - | tLBRACE assoc_list '}' - { - $$ = new_hash(p, $2); - } - | keyword_return - { - $$ = new_return(p, 0); - } - | keyword_yield '(' call_args rparen - { - $$ = new_yield(p, $3); - } - | keyword_yield '(' rparen - { - $$ = new_yield(p, 0); - } - | keyword_yield - { - $$ = new_yield(p, 0); - } - | keyword_not '(' expr rparen - { - $$ = call_uni_op(p, cond($3), "!"); - } - | keyword_not '(' rparen - { - $$ = call_uni_op(p, new_nil(p), "!"); - } - | operation brace_block - { - $$ = new_fcall(p, $1, cons(0, $2)); - } - | method_call - | method_call brace_block - { - call_with_block(p, $1, $2); - $$ = $1; - } - | tLAMBDA - { - local_nest(p); - $<num>$ = p->lpar_beg; - p->lpar_beg = ++p->paren_nest; - } - f_larglist - lambda_body - { - p->lpar_beg = $<num>2; - $$ = new_lambda(p, $3, $4); - local_unnest(p); - } - | keyword_if expr_value then - compstmt - if_tail - keyword_end - { - $$ = new_if(p, cond($2), $4, $5); - } - | keyword_unless expr_value then - compstmt - opt_else - keyword_end - { - $$ = new_unless(p, cond($2), $4, $5); - } - | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_while(p, cond($3), $6); - } - | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_until(p, cond($3), $6); - } - | keyword_case expr_value opt_terms - case_body - keyword_end - { - $$ = new_case(p, $2, $4); - } - | keyword_case opt_terms case_body keyword_end - { - $$ = new_case(p, 0, $3); - } - | keyword_for for_var keyword_in - {COND_PUSH(1);} - expr_value do - {COND_POP();} - compstmt - keyword_end - { - $$ = new_for(p, $2, $5, $8); - } - | keyword_class cpath superclass - { - if (p->in_def || p->in_single) - yyerror(p, "class definition in method body"); - $<nd>$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_class(p, $2, $3, $5); - local_resume(p, $<nd>4); - } - | keyword_class tLSHFT expr - { - $<num>$ = p->in_def; - p->in_def = 0; - } - term - { - $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); - p->in_single = 0; - } - bodystmt - keyword_end - { - $$ = new_sclass(p, $3, $7); - local_resume(p, $<nd>6->car); - p->in_def = $<num>4; - p->in_single = (int)(intptr_t)$<nd>6->cdr; - } - | keyword_module cpath - { - if (p->in_def || p->in_single) - yyerror(p, "module definition in method body"); - $<nd>$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_module(p, $2, $4); - local_resume(p, $<nd>3); - } - | keyword_def fname - { - p->in_def++; - $<nd>$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_def(p, $2, $4, $5); - local_resume(p, $<nd>3); - p->in_def--; - } - | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname - { - p->in_single++; - p->lstate = EXPR_ENDFN; /* force for args */ - $<nd>$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_sdef(p, $2, $5, $7, $8); - local_resume(p, $<nd>6); - p->in_single--; - } - | keyword_break - { - $$ = new_break(p, 0); - } - | keyword_next - { - $$ = new_next(p, 0); - } - | keyword_redo - { - $$ = new_redo(p); - } - | keyword_retry - { - $$ = new_retry(p); - } - ; - -primary_value : primary - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -then : term - | keyword_then - | term keyword_then - ; - -do : term - | keyword_do_cond - ; - -if_tail : opt_else - | keyword_elsif expr_value then - compstmt - if_tail - { - $$ = new_if(p, cond($2), $4, $5); - } - ; - -opt_else : none - | keyword_else compstmt - { - $$ = $2; - } - ; - -for_var : lhs - { - $$ = list1(list1($1)); - } - | mlhs - ; - -f_marg : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_marg_list : f_marg - { - $$ = list1($1); - } - | f_marg_list ',' f_marg - { - $$ = push($1, $3); - } - ; - -f_margs : f_marg_list - { - $$ = list3($1,0,0); - } - | f_marg_list ',' tSTAR f_norm_arg - { - $$ = list3($1, new_arg(p, $4), 0); - } - | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3($1, new_arg(p, $4), $6); - } - | f_marg_list ',' tSTAR - { - $$ = list3($1, (node*)-1, 0); - } - | f_marg_list ',' tSTAR ',' f_marg_list - { - $$ = list3($1, (node*)-1, $5); - } - | tSTAR f_norm_arg - { - $$ = list3(0, new_arg(p, $2), 0); - } - | tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3(0, new_arg(p, $2), $4); - } - | tSTAR - { - $$ = list3(0, (node*)-1, 0); - } - | tSTAR ',' f_marg_list - { - $$ = list3(0, (node*)-1, $3); - } - ; - -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_block_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' - { - $$ = new_args(p, $1, 0, 1, 0, 0); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_block_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - ; - -opt_block_param : none - | block_param_def - { - p->cmd_start = TRUE; - $$ = $1; - } - ; - -block_param_def : '|' opt_bv_decl '|' - { - local_add_f(p, 0); - $$ = 0; - } - | tOROP - { - local_add_f(p, 0); - $$ = 0; - } - | '|' block_param opt_bv_decl '|' - { - $$ = $2; - } - ; - - -opt_bv_decl : opt_nl - { - $$ = 0; - } - | opt_nl ';' bv_decls opt_nl - { - $$ = 0; - } - ; - -bv_decls : bvar - | bv_decls ',' bvar - ; - -bvar : tIDENTIFIER - { - local_add_f(p, $1); - new_bv(p, $1); - } - | f_bad_arg - ; - -f_larglist : '(' f_args opt_bv_decl ')' - { - $$ = $2; - } - | f_args - { - $$ = $1; - } - ; - -lambda_body : tLAMBEG compstmt '}' - { - $$ = $2; - } - | keyword_do_LAMBDA compstmt keyword_end - { - $$ = $2; - } - ; - -do_block : keyword_do_block - { - local_nest(p); - } - opt_block_param - compstmt - keyword_end - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - ; - -block_call : command do_block - { - if ($1->car == (node*)NODE_YIELD) { - yyerror(p, "block given to yield"); - } - else { - call_with_block(p, $1, $2); - } - $$ = $1; - } - | block_call dot_or_colon operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | block_call dot_or_colon operation2 opt_paren_args brace_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - | block_call dot_or_colon operation2 command_args do_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - ; - -method_call : operation paren_args - { - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation3 - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' paren_args - { - $$ = new_call(p, $1, 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); - } - opt_block_param - compstmt '}' - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - | keyword_do - { - local_nest(p); - } - opt_block_param - compstmt keyword_end - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - ; - -case_body : keyword_when args then - compstmt - cases - { - $$ = cons(cons($2, $4), $5); - } - ; - -cases : opt_else - { - if ($1) { - $$ = cons(cons(0, $1), 0); - } - else { - $$ = 0; - } - } - | case_body - ; - -opt_rescue : keyword_rescue exc_list exc_var then - compstmt - opt_rescue - { - $$ = list1(list3($2, $3, $5)); - if ($6) $$ = append($$, $6); - } - | none - ; - -exc_list : arg_value - { - $$ = list1($1); - } - | mrhs - | none - ; - -exc_var : tASSOC lhs - { - $$ = $2; - } - | none - ; - -opt_ensure : keyword_ensure compstmt - { - $$ = $2; - } - | none - ; - -literal : numeric - | symbol - | words - | symbols - ; - -string : tCHAR - | tSTRING - | tSTRING_BEG tSTRING - { - $$ = $2; - } - | tSTRING_BEG string_rep tSTRING - { - $$ = new_dstr(p, push($2, $3)); - } - ; +program : { + p->lstate = EXPR_BEG; + if (!p->locals) p->locals = cons(0,0); + } + top_compstmt + { + p->tree = new_scope(p, $2); + } + ; + +top_compstmt : top_stmts opt_terms + { + $$ = $1; + } + ; + +top_stmts : none + { + $$ = new_begin(p, 0); + } + | top_stmt + { + $$ = new_begin(p, $1); + } + | top_stmts terms top_stmt + { + $$ = push($1, newline_node($3)); + } + | error top_stmt + { + $$ = new_begin(p, 0); + } + ; + +top_stmt : stmt + | keyword_BEGIN + { + $<nd>$ = local_switch(p); + } + '{' top_compstmt '}' + { + yyerror(p, "BEGIN not supported"); + local_resume(p, $<nd>2); + $$ = 0; + } + ; + +bodystmt : compstmt + opt_rescue + opt_else + opt_ensure + { + if ($2) { + $$ = new_rescue(p, $1, $2, $3); + } + else if ($3) { + yywarn(p, "else without rescue is useless"); + $$ = push($1, $3); + } + else { + $$ = $1; + } + if ($4) { + if ($$) { + $$ = new_ensure(p, $$, $4); + } + else { + $$ = push($4, new_nil(p)); + } + } + } + ; + +compstmt : stmts opt_terms + { + $$ = $1; + } + ; + +stmts : none + { + $$ = new_begin(p, 0); + } + | stmt + { + $$ = new_begin(p, $1); + } + | stmts terms stmt + { + $$ = push($1, newline_node($3)); + } + | error stmt + { + $$ = new_begin(p, $2); + } + ; + +stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym + { + $$ = new_alias(p, $2, $4); + } + | keyword_undef undef_list + { + $$ = $2; + } + | stmt modifier_if expr_value + { + $$ = new_if(p, cond($3), $1, 0); + } + | stmt modifier_unless expr_value + { + $$ = new_unless(p, cond($3), $1, 0); + } + | stmt modifier_while expr_value + { + $$ = new_while(p, cond($3), $1); + } + | stmt modifier_until expr_value + { + $$ = new_until(p, cond($3), $1); + } + | stmt modifier_rescue stmt + { + $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); + } + | keyword_END '{' compstmt '}' + { + yyerror(p, "END not suported"); + $$ = new_postexe(p, $3); + } + | command_asgn + | mlhs '=' command_call + { + $$ = new_masgn(p, $1, $3); + } + | var_lhs tOP_ASGN command_call + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call + { + yyerror(p, "constant re-assignment"); + $$ = 0; + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | backref tOP_ASGN command_call + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | lhs '=' mrhs + { + $$ = new_asgn(p, $1, new_array(p, $3)); + } + | mlhs '=' arg_value + { + $$ = new_masgn(p, $1, $3); + } + | mlhs '=' mrhs + { + $$ = new_masgn(p, $1, new_array(p, $3)); + } + | expr + ; + +command_asgn : lhs '=' command_call + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' command_asgn + { + $$ = new_asgn(p, $1, $3); + } + ; + + +expr : command_call + | expr keyword_and expr + { + $$ = new_and(p, $1, $3); + } + | expr keyword_or expr + { + $$ = new_or(p, $1, $3); + } + | keyword_not opt_nl expr + { + $$ = call_uni_op(p, cond($3), "!"); + } + | '!' command_call + { + $$ = call_uni_op(p, cond($2), "!"); + } + | arg + ; + +expr_value : expr + { + if (!$1) $$ = new_nil(p); + else $$ = $1; + } + ; + +command_call : command + | block_command + ; + +block_command : block_call + | block_call dot_or_colon operation2 command_args + ; + +cmd_brace_block : tLBRACE_ARG + { + local_nest(p); + } + opt_block_param + compstmt + '}' + { + $$ = new_block(p, $3, $4); + local_unnest(p); + } + ; + +command : operation command_args %prec tLOWEST + { + $$ = new_fcall(p, $1, $2); + } + | operation command_args cmd_brace_block + { + args_with_block(p, $2, $3); + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value '.' operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | keyword_super command_args + { + $$ = new_super(p, $2); + } + | keyword_yield command_args + { + $$ = new_yield(p, $2); + } + | keyword_return call_args + { + $$ = new_return(p, ret_args(p, $2)); + } + | keyword_break call_args + { + $$ = new_break(p, ret_args(p, $2)); + } + | keyword_next call_args + { + $$ = new_next(p, ret_args(p, $2)); + } + ; + +mlhs : mlhs_basic + { + $$ = $1; + } + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_inner : mlhs_basic + | tLPAREN mlhs_inner rparen + { + $$ = list1($2); + } + ; + +mlhs_basic : mlhs_list + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = list1(push($1,$2)); + } + | mlhs_list tSTAR mlhs_node + { + $$ = list2($1, $3); + } + | mlhs_list tSTAR mlhs_node ',' mlhs_post + { + $$ = list3($1, $3, $5); + } + | mlhs_list tSTAR + { + $$ = list2($1, new_nil(p)); + } + | mlhs_list tSTAR ',' mlhs_post + { + $$ = list3($1, new_nil(p), $4); + } + | tSTAR mlhs_node + { + $$ = list2(0, $2); + } + | tSTAR mlhs_node ',' mlhs_post + { + $$ = list3(0, $2, $4); + } + | tSTAR + { + $$ = list2(0, new_nil(p)); + } + | tSTAR ',' mlhs_post + { + $$ = list3(0, new_nil(p), $3); + } + ; + +mlhs_item : mlhs_node + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_list : mlhs_item ',' + { + $$ = list1($1); + } + | mlhs_list mlhs_item ',' + { + $$ = push($1, $2); + } + ; + +mlhs_post : mlhs_item + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = push($1, $2); + } + ; + +mlhs_node : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +lhs : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +cname : tIDENTIFIER + { + yyerror(p, "class/module name must be CONSTANT"); + } + | tCONSTANT + ; + +cpath : tCOLON3 cname + { + $$ = cons((node*)1, nsym($2)); + } + | cname + { + $$ = cons((node*)0, nsym($1)); + } + | primary_value tCOLON2 cname + { + $$ = cons($1, nsym($3)); + } + ; + +fname : tIDENTIFIER + | tCONSTANT + | tFID + | op + { + p->lstate = EXPR_ENDFN; + $$ = $1; + } + | reswords + { + p->lstate = EXPR_ENDFN; + $$ = $<id>1; + } + ; + +fsym : fname + | basic_symbol + ; + +undef_list : fsym + { + $$ = new_undef(p, $1); + } + | undef_list ',' {p->lstate = EXPR_FNAME;} fsym + { + $$ = push($1, nsym($4)); + } + ; + +op : '|' { $$ = intern_c('|'); } + | '^' { $$ = intern_c('^'); } + | '&' { $$ = intern_c('&'); } + | tCMP { $$ = intern("<=>",3); } + | tEQ { $$ = intern("==",2); } + | tEQQ { $$ = intern("===",3); } + | tMATCH { $$ = intern("=~",2); } + | tNMATCH { $$ = intern("!~",2); } + | '>' { $$ = intern_c('>'); } + | tGEQ { $$ = intern(">=",2); } + | '<' { $$ = intern_c('<'); } + | tLEQ { $$ = intern("<=",2); } + | tNEQ { $$ = intern("!=",2); } + | tLSHFT { $$ = intern("<<",2); } + | tRSHFT { $$ = intern(">>",2); } + | '+' { $$ = intern_c('+'); } + | '-' { $$ = intern_c('-'); } + | '*' { $$ = intern_c('*'); } + | tSTAR { $$ = intern_c('*'); } + | '/' { $$ = intern_c('/'); } + | '%' { $$ = intern_c('%'); } + | tPOW { $$ = intern("**",2); } + | '!' { $$ = intern_c('!'); } + | '~' { $$ = intern_c('~'); } + | tUPLUS { $$ = intern("+@",2); } + | tUMINUS { $$ = intern("-@",2); } + | tAREF { $$ = intern("[]",2); } + | tASET { $$ = intern("[]=",3); } + | '`' { $$ = intern_c('`'); } + ; + +reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ + | keyword_BEGIN | keyword_END + | keyword_alias | keyword_and | keyword_begin + | keyword_break | keyword_case | keyword_class | keyword_def + | keyword_do | keyword_else | keyword_elsif + | keyword_end | keyword_ensure | keyword_false + | keyword_for | keyword_in | keyword_module | keyword_next + | keyword_nil | keyword_not | keyword_or | keyword_redo + | keyword_rescue | keyword_retry | keyword_return | keyword_self + | keyword_super | keyword_then | keyword_true | keyword_undef + | keyword_when | keyword_yield | keyword_if | keyword_unless + | keyword_while | keyword_until + ; + +arg : lhs '=' arg + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' arg modifier_rescue arg + { + $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | var_lhs tOP_ASGN arg + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | var_lhs tOP_ASGN arg modifier_rescue arg + { + $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | tCOLON3 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | backref tOP_ASGN arg + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | arg tDOT2 arg + { + $$ = new_dot2(p, $1, $3); + } + | arg tDOT3 arg + { + $$ = new_dot3(p, $1, $3); + } + | arg '+' arg + { + $$ = call_bin_op(p, $1, "+", $3); + } + | arg '-' arg + { + $$ = call_bin_op(p, $1, "-", $3); + } + | arg '*' arg + { + $$ = call_bin_op(p, $1, "*", $3); + } + | arg '/' arg + { + $$ = call_bin_op(p, $1, "/", $3); + } + | arg '%' arg + { + $$ = call_bin_op(p, $1, "%", $3); + } + | arg tPOW arg + { + $$ = call_bin_op(p, $1, "**", $3); + } + | tUMINUS_NUM tINTEGER tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUMINUS_NUM tFLOAT tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUPLUS arg + { + $$ = call_uni_op(p, $2, "+@"); + } + | tUMINUS arg + { + $$ = call_uni_op(p, $2, "-@"); + } + | arg '|' arg + { + $$ = call_bin_op(p, $1, "|", $3); + } + | arg '^' arg + { + $$ = call_bin_op(p, $1, "^", $3); + } + | arg '&' arg + { + $$ = call_bin_op(p, $1, "&", $3); + } + | arg tCMP arg + { + $$ = call_bin_op(p, $1, "<=>", $3); + } + | arg '>' arg + { + $$ = call_bin_op(p, $1, ">", $3); + } + | arg tGEQ arg + { + $$ = call_bin_op(p, $1, ">=", $3); + } + | arg '<' arg + { + $$ = call_bin_op(p, $1, "<", $3); + } + | arg tLEQ arg + { + $$ = call_bin_op(p, $1, "<=", $3); + } + | arg tEQ arg + { + $$ = call_bin_op(p, $1, "==", $3); + } + | arg tEQQ arg + { + $$ = call_bin_op(p, $1, "===", $3); + } + | arg tNEQ arg + { + $$ = call_bin_op(p, $1, "!=", $3); + } + | arg tMATCH arg + { + $$ = call_bin_op(p, $1, "=~", $3); + } + | arg tNMATCH arg + { + $$ = call_bin_op(p, $1, "!~", $3); + } + | '!' arg + { + $$ = call_uni_op(p, cond($2), "!"); + } + | '~' arg + { + $$ = call_uni_op(p, cond($2), "~"); + } + | arg tLSHFT arg + { + $$ = call_bin_op(p, $1, "<<", $3); + } + | arg tRSHFT arg + { + $$ = call_bin_op(p, $1, ">>", $3); + } + | arg tANDOP arg + { + $$ = new_and(p, $1, $3); + } + | arg tOROP arg + { + $$ = new_or(p, $1, $3); + } + | arg '?' arg opt_nl ':' arg + { + $$ = new_if(p, cond($1), $3, $6); + } + | primary + { + $$ = $1; + } + ; + +arg_value : arg + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +aref_args : none + | args trailer + { + $$ = $1; + } + | args ',' assocs trailer + { + $$ = push($1, new_hash(p, $3)); + } + | assocs trailer + { + $$ = cons(new_hash(p, $1), 0); + } + ; + +paren_args : '(' opt_call_args rparen + { + $$ = $2; + } + ; + +opt_paren_args : none + | paren_args + ; + +opt_call_args : none + | call_args + | args ',' + { + $$ = cons($1,0); + } + | args ',' assocs ',' + { + $$ = cons(push($1, new_hash(p, $3)), 0); + } + | assocs ',' + { + $$ = cons(list1(new_hash(p, $1)), 0); + } + ; + +call_args : command + { + $$ = cons(list1($1), 0); + } + | args opt_block_arg + { + $$ = cons($1, $2); + } + | assocs opt_block_arg + { + $$ = cons(list1(new_hash(p, $1)), $2); + } + | args ',' assocs opt_block_arg + { + $$ = cons(push($1, new_hash(p, $3)), $4); + } + | block_arg + { + $$ = cons(0, $1); + } + ; + +command_args : { + $<stack>$ = p->cmdarg_stack; + CMDARG_PUSH(1); + } + call_args + { + p->cmdarg_stack = $<stack>1; + $$ = $2; + } + ; + +block_arg : tAMPER arg_value + { + $$ = new_block_arg(p, $2); + } + ; + +opt_block_arg : ',' block_arg + { + $$ = $2; + } + | none + { + $$ = 0; + } + ; + +args : arg_value + { + $$ = cons($1, 0); + } + | tSTAR arg_value + { + $$ = cons(new_splat(p, $2), 0); + } + | args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | args ',' heredoc_bodies arg_value + { + $$ = push($1, $4); + } + | args ',' heredoc_bodies tSTAR arg_value + { + $$ = push($1, new_splat(p, $5)); + } + ; + +mrhs : args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | tSTAR arg_value + { + $$ = list1(new_splat(p, $2)); + } + ; + +primary : literal + | string + | xstring + | regexp + | heredoc + | var_ref + | backref + | tFID + { + $$ = new_fcall(p, $1, 0); + } + | keyword_begin + { + $<stack>1 = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + bodystmt + keyword_end + { + p->cmdarg_stack = $<stack>1; + $$ = $3; + } + | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen + { + $$ = $2; + } + | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen + { + $$ = 0; + } + | tLPAREN compstmt ')' + { + $$ = $2; + } + | primary_value tCOLON2 tCONSTANT + { + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + $$ = new_colon3(p, $2); + } + | tLBRACK aref_args ']' + { + $$ = new_array(p, $2); + } + | tLBRACE assoc_list '}' + { + $$ = new_hash(p, $2); + } + | keyword_return + { + $$ = new_return(p, 0); + } + | keyword_yield '(' call_args rparen + { + $$ = new_yield(p, $3); + } + | keyword_yield '(' rparen + { + $$ = new_yield(p, 0); + } + | keyword_yield + { + $$ = new_yield(p, 0); + } + | keyword_not '(' expr rparen + { + $$ = call_uni_op(p, cond($3), "!"); + } + | keyword_not '(' rparen + { + $$ = call_uni_op(p, new_nil(p), "!"); + } + | operation brace_block + { + $$ = new_fcall(p, $1, cons(0, $2)); + } + | method_call + | method_call brace_block + { + call_with_block(p, $1, $2); + $$ = $1; + } + | tLAMBDA + { + local_nest(p); + $<num>$ = p->lpar_beg; + p->lpar_beg = ++p->paren_nest; + } + f_larglist + lambda_body + { + p->lpar_beg = $<num>2; + $$ = new_lambda(p, $3, $4); + local_unnest(p); + } + | keyword_if expr_value then + compstmt + if_tail + keyword_end + { + $$ = new_if(p, cond($2), $4, $5); + } + | keyword_unless expr_value then + compstmt + opt_else + keyword_end + { + $$ = new_unless(p, cond($2), $4, $5); + } + | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_while(p, cond($3), $6); + } + | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_until(p, cond($3), $6); + } + | keyword_case expr_value opt_terms + case_body + keyword_end + { + $$ = new_case(p, $2, $4); + } + | keyword_case opt_terms case_body keyword_end + { + $$ = new_case(p, 0, $3); + } + | keyword_for for_var keyword_in + {COND_PUSH(1);} + expr_value do + {COND_POP();} + compstmt + keyword_end + { + $$ = new_for(p, $2, $5, $8); + } + | keyword_class + { + $<num>$ = p->lineno; + } + cpath superclass + { + if (p->in_def || p->in_single) + yyerror(p, "class definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_class(p, $3, $4, $6); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>5); + } + | keyword_class + { + $<num>$ = p->lineno; + } + tLSHFT expr + { + $<num>$ = p->in_def; + p->in_def = 0; + } + term + { + $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); + p->in_single = 0; + } + bodystmt + keyword_end + { + $$ = new_sclass(p, $4, $8); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>7->car); + p->in_def = $<num>5; + p->in_single = (int)(intptr_t)$<nd>7->cdr; + } + | keyword_module + { + $<num>$ = p->lineno; + } + cpath + { + if (p->in_def || p->in_single) + yyerror(p, "module definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_module(p, $3, $5); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>4); + } + | keyword_def fname + { + p->in_def++; + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_def(p, $2, $4, $5); + local_resume(p, $<nd>3); + p->in_def--; + } + | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname + { + p->in_single++; + p->lstate = EXPR_ENDFN; /* force for args */ + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_sdef(p, $2, $5, $7, $8); + local_resume(p, $<nd>6); + p->in_single--; + } + | keyword_break + { + $$ = new_break(p, 0); + } + | keyword_next + { + $$ = new_next(p, 0); + } + | keyword_redo + { + $$ = new_redo(p); + } + | keyword_retry + { + $$ = new_retry(p); + } + ; + +primary_value : primary + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +then : term + | keyword_then + | term keyword_then + ; + +do : term + | keyword_do_cond + ; + +if_tail : opt_else + | keyword_elsif expr_value then + compstmt + if_tail + { + $$ = new_if(p, cond($2), $4, $5); + } + ; + +opt_else : none + | keyword_else compstmt + { + $$ = $2; + } + ; + +for_var : lhs + { + $$ = list1(list1($1)); + } + | mlhs + ; + +f_marg : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_marg_list : f_marg + { + $$ = list1($1); + } + | f_marg_list ',' f_marg + { + $$ = push($1, $3); + } + ; + +f_margs : f_marg_list + { + $$ = list3($1,0,0); + } + | f_marg_list ',' tSTAR f_norm_arg + { + $$ = list3($1, new_arg(p, $4), 0); + } + | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3($1, new_arg(p, $4), $6); + } + | f_marg_list ',' tSTAR + { + $$ = list3($1, (node*)-1, 0); + } + | f_marg_list ',' tSTAR ',' f_marg_list + { + $$ = list3($1, (node*)-1, $5); + } + | tSTAR f_norm_arg + { + $$ = list3(0, new_arg(p, $2), 0); + } + | tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3(0, new_arg(p, $2), $4); + } + | tSTAR + { + $$ = list3(0, (node*)-1, 0); + } + | tSTAR ',' f_marg_list + { + $$ = list3(0, (node*)-1, $3); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_block_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' + { + $$ = new_args(p, $1, 0, 1, 0, 0); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_block_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + ; + +opt_block_param : none + | block_param_def + { + p->cmd_start = TRUE; + $$ = $1; + } + ; + +block_param_def : '|' opt_bv_decl '|' + { + local_add_f(p, 0); + $$ = 0; + } + | tOROP + { + local_add_f(p, 0); + $$ = 0; + } + | '|' block_param opt_bv_decl '|' + { + $$ = $2; + } + ; + + +opt_bv_decl : opt_nl + { + $$ = 0; + } + | opt_nl ';' bv_decls opt_nl + { + $$ = 0; + } + ; + +bv_decls : bvar + | bv_decls ',' bvar + ; + +bvar : tIDENTIFIER + { + local_add_f(p, $1); + new_bv(p, $1); + } + | f_bad_arg + ; + +f_larglist : '(' f_args opt_bv_decl ')' + { + $$ = $2; + } + | f_args + { + $$ = $1; + } + ; + +lambda_body : tLAMBEG compstmt '}' + { + $$ = $2; + } + | keyword_do_LAMBDA compstmt keyword_end + { + $$ = $2; + } + ; + +do_block : keyword_do_block + { + local_nest(p); + } + opt_block_param + compstmt + keyword_end + { + $$ = new_block(p,$3,$4); + local_unnest(p); + } + ; + +block_call : command do_block + { + if ($1->car == (node*)NODE_YIELD) { + yyerror(p, "block given to yield"); + } + else { + call_with_block(p, $1, $2); + } + $$ = $1; + } + | block_call dot_or_colon operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | block_call dot_or_colon operation2 opt_paren_args brace_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + | block_call dot_or_colon operation2 command_args do_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + ; + +method_call : operation paren_args + { + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation3 + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | primary_value tCOLON2 paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | keyword_super paren_args + { + $$ = new_super(p, $2); + } + | keyword_super + { + $$ = new_zsuper(p); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + ; + +brace_block : '{' + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt '}' + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + | keyword_do + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt keyword_end + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + ; + +case_body : keyword_when args then + compstmt + cases + { + $$ = cons(cons($2, $4), $5); + } + ; + +cases : opt_else + { + if ($1) { + $$ = cons(cons(0, $1), 0); + } + else { + $$ = 0; + } + } + | case_body + ; + +opt_rescue : keyword_rescue exc_list exc_var then + compstmt + opt_rescue + { + $$ = list1(list3($2, $3, $5)); + if ($6) $$ = append($$, $6); + } + | none + ; + +exc_list : arg_value + { + $$ = list1($1); + } + | mrhs + | none + ; + +exc_var : tASSOC lhs + { + $$ = $2; + } + | none + ; + +opt_ensure : keyword_ensure compstmt + { + $$ = $2; + } + | none + ; + +literal : numeric + | symbol + | words + | symbols + ; + +string : tCHAR + | tSTRING + | tSTRING_BEG tSTRING + { + $$ = $2; + } + | tSTRING_BEG string_rep tSTRING + { + $$ = new_dstr(p, push($2, $3)); + } + ; string_rep : string_interp - | string_rep string_interp - { - $$ = append($1, $2); - } - ; - -string_interp : tSTRING_MID - { - $$ = list1($1); - } - | tSTRING_PART - { - $<nd>$ = p->lex_strterm; - p->lex_strterm = NULL; - } - compstmt - '}' - { - p->lex_strterm = $<nd>2; - $$ = list2($1, $3); - } - | tLITERAL_DELIM - { - $$ = list1(new_literal_delim(p)); - } - | 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 - ; + | 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_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_rep heredoc_string_interp + ; heredoc_string_interp : tHD_STRING_MID - { - parser_heredoc_info * inf = parsing_heredoc_inf(p); - inf->doc = push(inf->doc, $1); - heredoc_treat_nextline(p); - } - | tHD_STRING_PART - { - $<nd>$ = p->lex_strterm; - p->lex_strterm = NULL; - } - compstmt - '}' - { - parser_heredoc_info * inf = parsing_heredoc_inf(p); - p->lex_strterm = $<nd>2; - inf->doc = push(push(inf->doc, $1), $3); - } - ; - -words : tWORDS_BEG tSTRING - { - $$ = new_words(p, list1($2)); - } - | tWORDS_BEG string_rep tSTRING - { - $$ = new_words(p, push($2, $3)); - } - ; - - -symbol : basic_symbol - { - $$ = new_sym(p, $1); - } - | tSYMBEG tSTRING_BEG string_interp tSTRING - { - p->lstate = EXPR_END; - $$ = new_dsym(p, push($3, $4)); - } - ; - -basic_symbol : tSYMBEG sym - { - p->lstate = EXPR_END; - $$ = $2; - } - ; - -sym : fname - | tIVAR - | tGVAR - | tCVAR - | tSTRING - { - $$ = new_strsym(p, $1); - } - | tSTRING_BEG tSTRING - { - $$ = new_strsym(p, $2); - } - ; - -symbols : tSYMBOLS_BEG tSTRING - { - $$ = new_symbols(p, list1($2)); - } - | tSYMBOLS_BEG string_rep tSTRING - { - $$ = new_symbols(p, push($2, $3)); - } - ; - -numeric : tINTEGER - | tFLOAT - | tUMINUS_NUM tINTEGER %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - | tUMINUS_NUM tFLOAT %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - ; - -variable : tIDENTIFIER - { - $$ = new_lvar(p, $1); - } - | tIVAR - { - $$ = new_ivar(p, $1); - } - | tGVAR - { - $$ = new_gvar(p, $1); - } - | tCVAR - { - $$ = new_cvar(p, $1); - } - | tCONSTANT - { - $$ = new_const(p, $1); - } - ; - -var_lhs : variable - { - assignable(p, $1); - } - ; - -var_ref : variable - { - $$ = var_reference(p, $1); - } - | keyword_nil - { - $$ = new_nil(p); - } - | keyword_self - { - $$ = new_self(p); - } - | keyword_true - { - $$ = new_true(p); - } - | keyword_false - { - $$ = new_false(p); - } - | keyword__FILE__ - { - if (!p->filename) { - p->filename = "(null)"; - } - $$ = new_str(p, p->filename, strlen(p->filename)); - } - | keyword__LINE__ - { - char buf[16]; - - snprintf(buf, sizeof(buf), "%d", p->lineno); - $$ = new_int(p, buf, 10); - } - ; - -backref : tNTH_REF - | tBACK_REF - ; - -superclass : term - { - $$ = 0; - } - | '<' - { - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - expr_value term - { - $$ = $3; - } - | error term - { - yyerrok; - $$ = 0; - } - ; - -f_arglist : '(' f_args rparen - { - $$ = $2; - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - | f_args term - { - $$ = $1; - } - ; - -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - | /* none */ - { - local_add_f(p, 0); - $$ = new_args(p, 0, 0, 0, 0, 0); - } - ; - -f_bad_arg : tCONSTANT - { - yyerror(p, "formal argument cannot be a constant"); - $$ = 0; - } - | tIVAR - { - yyerror(p, "formal argument cannot be an instance variable"); - $$ = 0; - } - | tGVAR - { - yyerror(p, "formal argument cannot be a global variable"); - $$ = 0; - } - | tCVAR - { - yyerror(p, "formal argument cannot be a class variable"); - $$ = 0; - } - ; - -f_norm_arg : f_bad_arg - { - $$ = 0; - } - | tIDENTIFIER - { - local_add_f(p, $1); - $$ = $1; - } - ; - -f_arg_item : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_arg : f_arg_item - { - $$ = list1($1); - } - | f_arg ',' f_arg_item - { - $$ = push($1, $3); - } - ; - -f_opt : tIDENTIFIER '=' arg_value - { - local_add_f(p, $1); - $$ = cons(nsym($1), $3); - } - ; - -f_block_opt : tIDENTIFIER '=' primary_value - { - local_add_f(p, $1); - $$ = cons(nsym($1), $3); - } - ; - -f_block_optarg : f_block_opt - { - $$ = list1($1); - } - | f_block_optarg ',' f_block_opt - { - $$ = push($1, $3); - } - ; - -f_optarg : f_opt - { - $$ = list1($1); - } - | f_optarg ',' f_opt - { - $$ = push($1, $3); - } - ; - -restarg_mark : '*' - | tSTAR - ; - -f_rest_arg : restarg_mark tIDENTIFIER - { - local_add_f(p, $2); - $$ = $2; - } - | restarg_mark - { - local_add_f(p, 0); - $$ = -1; - } - ; - -blkarg_mark : '&' - | tAMPER - ; - -f_block_arg : blkarg_mark tIDENTIFIER - { - local_add_f(p, $2); - $$ = $2; - } - ; - -opt_f_block_arg : ',' f_block_arg - { - $$ = $2; - } - | none - { - local_add_f(p, 0); - $$ = 0; - } - ; - -singleton : var_ref - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - | '(' {p->lstate = EXPR_BEG;} expr rparen - { - if ($3 == 0) { - yyerror(p, "can't define singleton method for ()."); - } - else { - switch ((enum node_type)(int)(intptr_t)$3->car) { - case NODE_STR: - case NODE_DSTR: - case NODE_XSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_MATCH: - case NODE_FLOAT: - case NODE_ARRAY: - case NODE_HEREDOC: - yyerror(p, "can't define singleton method for literals"); - default: - break; - } - } - $$ = $3; - } - ; - -assoc_list : none - | assocs trailer - { - $$ = $1; - } - ; - -assocs : assoc - { - $$ = list1($1); - } - | assocs ',' assoc - { - $$ = push($1, $3); - } - ; - -assoc : arg_value tASSOC arg_value - { - $$ = cons($1, $3); - } - | tLABEL arg_value - { - $$ = cons(new_sym(p, $1), $2); - } - ; - -operation : tIDENTIFIER - | tCONSTANT - | tFID - ; - -operation2 : tIDENTIFIER - | tCONSTANT - | tFID - | op - ; - -operation3 : tIDENTIFIER - | tFID - | op - ; - -dot_or_colon : '.' - | tCOLON2 - ; - -opt_terms : /* none */ - | terms - ; - -opt_nl : /* none */ - | nl - ; - -rparen : opt_nl ')' - ; - -rbracket : opt_nl ']' - ; - -trailer : /* none */ - | nl - | ',' - ; - -term : ';' {yyerrok;} - | nl - ; - -nl : '\n' - { - p->lineno++; - p->column = 0; - } - opt_heredoc_bodies - -terms : term - | terms ';' {yyerrok;} - ; - -none : /* none */ - { - $$ = 0; - } - ; + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, $1); + heredoc_treat_nextline(p); + } + | tHD_STRING_PART + { + $<nd>$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + p->lex_strterm = $<nd>2; + inf->doc = push(push(inf->doc, $1), $3); + } + ; + +words : tWORDS_BEG tSTRING + { + $$ = new_words(p, list1($2)); + } + | tWORDS_BEG string_rep tSTRING + { + $$ = new_words(p, push($2, $3)); + } + ; + + +symbol : basic_symbol + { + $$ = new_sym(p, $1); + } + | tSYMBEG tSTRING_BEG string_interp tSTRING + { + p->lstate = EXPR_END; + $$ = new_dsym(p, push($3, $4)); + } + ; + +basic_symbol : tSYMBEG sym + { + p->lstate = EXPR_END; + $$ = $2; + } + ; + +sym : fname + | tIVAR + | tGVAR + | tCVAR + | tSTRING + { + $$ = new_strsym(p, $1); + } + | tSTRING_BEG tSTRING + { + $$ = new_strsym(p, $2); + } + ; + +symbols : tSYMBOLS_BEG tSTRING + { + $$ = new_symbols(p, list1($2)); + } + | tSYMBOLS_BEG string_rep tSTRING + { + $$ = new_symbols(p, push($2, $3)); + } + ; + +numeric : tINTEGER + | tFLOAT + | tUMINUS_NUM tINTEGER %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + | tUMINUS_NUM tFLOAT %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + ; + +variable : tIDENTIFIER + { + $$ = new_lvar(p, $1); + } + | tIVAR + { + $$ = new_ivar(p, $1); + } + | tGVAR + { + $$ = new_gvar(p, $1); + } + | tCVAR + { + $$ = new_cvar(p, $1); + } + | tCONSTANT + { + $$ = new_const(p, $1); + } + ; + +var_lhs : variable + { + assignable(p, $1); + } + ; + +var_ref : variable + { + $$ = var_reference(p, $1); + } + | keyword_nil + { + $$ = new_nil(p); + } + | keyword_self + { + $$ = new_self(p); + } + | keyword_true + { + $$ = new_true(p); + } + | keyword_false + { + $$ = new_false(p); + } + | keyword__FILE__ + { + if (!p->filename) { + p->filename = "(null)"; + } + $$ = new_str(p, p->filename, strlen(p->filename)); + } + | keyword__LINE__ + { + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", p->lineno); + $$ = new_int(p, buf, 10); + } + ; + +backref : tNTH_REF + | tBACK_REF + ; + +superclass : term + { + $$ = 0; + } + | '<' + { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + expr_value term + { + $$ = $3; + } + | error term + { + yyerrok; + $$ = 0; + } + ; + +f_arglist : '(' f_args rparen + { + $$ = $2; + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + | f_args term + { + $$ = $1; + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + | /* none */ + { + local_add_f(p, 0); + $$ = new_args(p, 0, 0, 0, 0, 0); + } + ; + +f_bad_arg : tCONSTANT + { + yyerror(p, "formal argument cannot be a constant"); + $$ = 0; + } + | tIVAR + { + yyerror(p, "formal argument cannot be an instance variable"); + $$ = 0; + } + | tGVAR + { + yyerror(p, "formal argument cannot be a global variable"); + $$ = 0; + } + | tCVAR + { + yyerror(p, "formal argument cannot be a class variable"); + $$ = 0; + } + ; + +f_norm_arg : f_bad_arg + { + $$ = 0; + } + | tIDENTIFIER + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_arg_item : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_arg : f_arg_item + { + $$ = list1($1); + } + | f_arg ',' f_arg_item + { + $$ = push($1, $3); + } + ; + +f_opt : tIDENTIFIER '=' arg_value + { + local_add_f(p, $1); + $$ = cons(nsym($1), $3); + } + ; + +f_block_opt : tIDENTIFIER '=' primary_value + { + local_add_f(p, $1); + $$ = cons(nsym($1), $3); + } + ; + +f_block_optarg : f_block_opt + { + $$ = list1($1); + } + | f_block_optarg ',' f_block_opt + { + $$ = push($1, $3); + } + ; + +f_optarg : f_opt + { + $$ = list1($1); + } + | f_optarg ',' f_opt + { + $$ = push($1, $3); + } + ; + +restarg_mark : '*' + | tSTAR + ; + +f_rest_arg : restarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + | restarg_mark + { + local_add_f(p, 0); + $$ = -1; + } + ; + +blkarg_mark : '&' + | tAMPER + ; + +f_block_arg : blkarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + ; + +opt_f_block_arg : ',' f_block_arg + { + $$ = $2; + } + | none + { + local_add_f(p, 0); + $$ = 0; + } + ; + +singleton : var_ref + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + | '(' {p->lstate = EXPR_BEG;} expr rparen + { + if ($3 == 0) { + yyerror(p, "can't define singleton method for ()."); + } + else { + switch ((enum node_type)(int)(intptr_t)$3->car) { + case NODE_STR: + case NODE_DSTR: + case NODE_XSTR: + case NODE_DXSTR: + case NODE_DREGX: + case NODE_MATCH: + case NODE_FLOAT: + case NODE_ARRAY: + case NODE_HEREDOC: + yyerror(p, "can't define singleton method for literals"); + default: + break; + } + } + $$ = $3; + } + ; + +assoc_list : none + | assocs trailer + { + $$ = $1; + } + ; + +assocs : assoc + { + $$ = list1($1); + } + | assocs ',' assoc + { + $$ = push($1, $3); + } + ; + +assoc : arg_value tASSOC arg_value + { + $$ = cons($1, $3); + } + | tLABEL arg_value + { + $$ = cons(new_sym(p, $1), $2); + } + ; + +operation : tIDENTIFIER + | tCONSTANT + | tFID + ; + +operation2 : tIDENTIFIER + | tCONSTANT + | tFID + | op + ; + +operation3 : tIDENTIFIER + | tFID + | op + ; + +dot_or_colon : '.' + | tCOLON2 + ; + +opt_terms : /* none */ + | terms + ; + +opt_nl : /* none */ + | nl + ; + +rparen : opt_nl ')' + ; + +rbracket : opt_nl ']' + ; + +trailer : /* none */ + | nl + | ',' + ; + +term : ';' {yyerrok;} + | nl + ; + +nl : '\n' + { + p->lineno++; + p->column = 0; + } + opt_heredoc_bodies + +terms : term + | terms ';' {yyerrok;} + ; + +none : /* none */ + { + $$ = 0; + } + ; %% #define yylval (*((YYSTYPE*)(p->ylval))) @@ -3322,26 +3344,22 @@ nextc(parser_state *p) } else #endif - if (!p->s || p->s >= p->send) { - goto eof; - } - else { - c = (unsigned char)*p->s++; - } + if (!p->s || p->s >= p->send) { + goto eof; + } + else { + c = (unsigned char)*p->s++; + } } p->column++; return c; - eof: + eof: if (!p->cxt) return -1; else { - mrbc_context *cxt = p->cxt; - - if (cxt->partial_hook(p) < 0) return -1; - c = '\n'; - p->lineno = 1; - p->cxt = cxt; - return c; + if (p->cxt->partial_hook(p) < 0) + return -1; + return -2; } } @@ -3402,9 +3420,9 @@ peeks(parser_state *p, const char *s) } else #endif - if (p->s && p->s + len >= p->send) { - if (memcmp(p->s, s, len) == 0) return TRUE; - } + if (p->s && p->s + len >= p->send) { + if (memcmp(p->s, s, len) == 0) return TRUE; + } return FALSE; } @@ -3425,11 +3443,11 @@ skips(parser_state *p, const char *s) int len = strlen(s); while (len--) { - nextc(p); + nextc(p); } return TRUE; } - else{ + else{ s--; } } @@ -3527,74 +3545,74 @@ read_escape(parser_state *p) int c; switch (c = nextc(p)) { - case '\\': /* Backslash */ + case '\\':/* Backslash */ return c; - case 'n': /* newline */ + case 'n':/* newline */ return '\n'; - case 't': /* horizontal tab */ + case 't':/* horizontal tab */ return '\t'; - case 'r': /* carriage-return */ + case 'r':/* carriage-return */ return '\r'; - case 'f': /* form-feed */ + case 'f':/* form-feed */ return '\f'; - case 'v': /* vertical tab */ + case 'v':/* vertical tab */ return '\13'; - case 'a': /* alarm(bell) */ + case 'a':/* alarm(bell) */ return '\007'; - case 'e': /* escape */ + case 'e':/* escape */ return 033; case '0': case '1': case '2': case '3': /* octal constant */ case '4': case '5': case '6': case '7': - { - int buf[3]; - int i; - - buf[0] = c; - for (i=1; i<3; i++) { - buf[i] = nextc(p); - if (buf[i] == -1) goto eof; - if (buf[i] < '0' || '7' < buf[i]) { - pushback(p, buf[i]); - break; - } + { + 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; + c = scan_oct(buf, i, &i); + } + return c; - case 'x': /* hex constant */ - { - int buf[2]; - int i; - - for (i=0; i<2; i++) { - buf[i] = nextc(p); - if (buf[i] == -1) goto eof; - if (!ISXDIGIT(buf[i])) { - pushback(p, buf[i]); - break; - } - } - c = scan_hex(buf, i, &i); - if (i == 0) { - yyerror(p, "Invalid escape character syntax"); - return 0; + 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; } } - return c; + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + } + return c; - case 'b': /* backspace */ + case 'b':/* backspace */ return '\010'; - case 's': /* space */ + case 's':/* space */ return ' '; case 'M': @@ -3606,7 +3624,7 @@ read_escape(parser_state *p) if ((c = nextc(p)) == '\\') { return read_escape(p) | 0x80; } - else if (c == -1) goto eof; + else if (c < 0) goto eof; else { return ((c & 0xff) | 0x80); } @@ -3623,11 +3641,12 @@ read_escape(parser_state *p) } else if (c == '?') return 0177; - else if (c == -1) goto eof; + else if (c < 0) goto eof; return c & 0x9f; - eof: + eof: case -1: + case -2: yyerror(p, "Invalid escape character syntax"); return '\0'; @@ -3649,7 +3668,7 @@ parse_string(parser_state *p) newtok(p); while ((c = nextc(p)) != end || nest_level != 0) { - if (hinf && (c == '\n' || c == -1)) { + if (hinf && (c == '\n' || c < 0)) { int line_head; tokadd(p, '\n'); tokfix(p); @@ -3658,29 +3677,29 @@ parse_string(parser_state *p) line_head = hinf->line_head; hinf->line_head = TRUE; if (line_head) { - /* check whether end of heredoc */ - const char *s = tok(p); - int len = toklen(p); - if (hinf->allow_indent) { - while (ISSPACE(*s) && len > 0) { - ++s; - --len; - } - } - if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { - return tHEREDOC_END; - } + /* check whether end of heredoc */ + const char *s = tok(p); + int len = toklen(p); + if (hinf->allow_indent) { + while (ISSPACE(*s) && len > 0) { + ++s; + --len; + } + } + if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { + return tHEREDOC_END; + } } - if (c == -1) { - char buf[256]; - snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); - yyerror(p, buf); - return 0; + if (c < 0) { + char buf[256]; + snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + yyerror(p, buf); + return 0; } yylval.nd = new_str(p, tok(p), toklen(p)); return tHD_STRING_MID; } - if (c == -1) { + if (c < 0) { yyerror(p, "unterminated string meets end of file"); return 0; } @@ -3695,58 +3714,58 @@ parse_string(parser_state *p) else if (c == '\\') { c = nextc(p); if (type & STR_FUNC_EXPAND) { - if (c == end || c == beg) { - tokadd(p, c); - } - else if ((c == '\n') && (type & STR_FUNC_ARRAY)) { - p->lineno++; - p->column = 0; - tokadd(p, '\n'); - } - else { - if (type & STR_FUNC_REGEXP) { - tokadd(p, '\\'); - if (c != -1) - tokadd(p, c); - } else { - pushback(p, c); - tokadd(p, read_escape(p)); - } - if (hinf) - hinf->line_head = FALSE; - } + if (c == end || c == beg) { + tokadd(p, c); + } + else if ((c == '\n') && (type & STR_FUNC_ARRAY)) { + p->lineno++; + p->column = 0; + tokadd(p, '\n'); + } + else { + if (type & STR_FUNC_REGEXP) { + tokadd(p, '\\'); + if (c >= 0) + tokadd(p, c); + } else { + pushback(p, c); + tokadd(p, read_escape(p)); + } + if (hinf) + hinf->line_head = FALSE; + } } else { - if (c != beg && c != end) { - switch (c) { - case '\n': - p->lineno++; - p->column = 0; - break; - - case '\\': - break; - - default: - if (! ISSPACE(c)) - tokadd(p, '\\'); - } - } - tokadd(p, c); + if (c != beg && c != end) { + switch (c) { + case '\n': + p->lineno++; + p->column = 0; + break; + + case '\\': + break; + + default: + if (! 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; + 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); @@ -3754,23 +3773,23 @@ parse_string(parser_state *p) } if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { if (toklen(p) == 0) { - do { - if (c == '\n') { - p->lineno++; - p->column = 0; - heredoc_treat_nextline(p); - if (p->parsing_heredoc != NULL) { - return tHD_LITERAL_DELIM; - } - } - } while (ISSPACE(c = nextc(p))); - pushback(p, c); - return tLITERAL_DELIM; + do { + if (c == '\n') { + p->lineno++; + p->column = 0; + heredoc_treat_nextline(p); + if (p->parsing_heredoc != NULL) { + return tHD_LITERAL_DELIM; + } + } + } while (ISSPACE(c = nextc(p))); + pushback(p, c); + return tLITERAL_DELIM; } else { - pushback(p, c); - tokfix(p); - yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING_MID; + pushback(p, c); + tokfix(p); + yylval.nd = new_str(p, tok(p), toklen(p)); + return tSTRING_MID; } } @@ -3796,7 +3815,7 @@ parse_string(parser_state *p) char *dup; newtok(p); - while (c = nextc(p), c != -1 && ISALPHA(c)) { + while (c = nextc(p), c >= 0 && ISALPHA(c)) { switch (c) { case 'i': f |= 1; break; case 'x': f |= 2; break; @@ -3809,7 +3828,7 @@ parse_string(parser_state *p) char msg[128]; tokfix(p); snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); + toklen(p) > 1 ? "s" : "", tok(p)); yyerror(p, msg); } if (f != 0) { @@ -3855,19 +3874,19 @@ heredoc_identifier(parser_state *p) if (c == '\'') quote = TRUE; newtok(p); - while ((c = nextc(p)) != -1 && c != term) { + while ((c = nextc(p)) >= 0 && c != term) { if (c == '\n') { - c = -1; - break; + c = -1; + break; } tokadd(p, c); } - if (c == -1) { + if (c < 0) { yyerror(p, "unterminated here document identifier"); return 0; } } else { - if (c == -1) { + if (c < 0) { return 0; /* missing here document identifier */ } if (! identchar(c)) { @@ -3878,7 +3897,7 @@ heredoc_identifier(parser_state *p) newtok(p); do { tokadd(p, c); - } while ((c = nextc(p)) != -1 && identchar(c)); + } while ((c = nextc(p)) >= 0 && identchar(c)); pushback(p, c); } tokfix(p); @@ -3920,14 +3939,14 @@ parser_yylex(parser_state *p) if (p->lex_strterm) { if (is_strterm_type(p, STR_FUNC_HEREDOC)) { if (p->parsing_heredoc != NULL) - return parse_string(p); + return parse_string(p); } else return parse_string(p); } cmd_state = p->cmd_start; p->cmd_start = FALSE; - retry: + retry: last_state = p->lstate; switch (c = nextc(p)) { case '\0': /* NUL */ @@ -3947,78 +3966,80 @@ parser_yylex(parser_state *p) case '#': /* it's a comment */ skip(p, '\n'); - /* fall through */ + /* fall through */ + case -2: /* end of partial script. */ case '\n': - maybe_heredoc: + 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) { - return parse_string(p); - } - goto retry; - default: - break; - } + 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) { - return '\n'; + return parse_string(p); } - while ((c = nextc(p))) { - switch (c) { - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - break; - case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); - pushback(p, '.'); - goto retry; - } - case -1: /* EOF */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; + 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 partial script */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; } + } normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; case '*': if ((c = nextc(p)) == '*') { if ((c = nextc(p)) == '=') { - yylval.id = intern("**",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("**",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); c = tPOW; } else { if (c == '=') { - yylval.id = intern_c('*'); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern_c('*'); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`*' interpreted as argument prefix"); - c = tSTAR; + yywarning(p, "`*' interpreted as argument prefix"); + c = tSTAR; } else if (IS_BEG()) { - c = tSTAR; + c = tSTAR; } else { - c = '*'; + c = '*'; } } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { @@ -4033,7 +4054,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return '!'; + return '!'; } } else { @@ -4051,8 +4072,8 @@ parser_yylex(parser_state *p) case '=': if (p->column == 1) { if (peeks(p, "begin\n")) { - skips(p, "\n=end\n"); - goto retry; + skips(p, "\n=end\n"); + goto retry; } } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { @@ -4062,7 +4083,7 @@ parser_yylex(parser_state *p) } if ((c = nextc(p)) == '=') { if ((c = nextc(p)) == '=') { - return tEQQ; + return tEQQ; } pushback(p, c); return tEQ; @@ -4080,34 +4101,34 @@ parser_yylex(parser_state *p) last_state = p->lstate; c = nextc(p); if (c == '<' && - p->lstate != EXPR_DOT && - p->lstate != EXPR_CLASS && - !IS_END() && - (!IS_ARG() || space_seen)) { + p->lstate != EXPR_DOT && + p->lstate != EXPR_CLASS && + !IS_END() && + (!IS_ARG() || space_seen)) { int token = heredoc_identifier(p); if (token) - return token; + return token; } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; } else { p->lstate = EXPR_BEG; if (p->lstate == EXPR_CLASS) { - p->cmd_start = TRUE; + p->cmd_start = TRUE; } } if (c == '=') { if ((c = nextc(p)) == '>') { - return tCMP; + return tCMP; } pushback(p, c); return tLEQ; } if (c == '<') { if ((c = nextc(p)) == '=') { - yylval.id = intern("<<",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("<<",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tLSHFT; @@ -4126,9 +4147,9 @@ parser_yylex(parser_state *p) } if (c == '>') { if ((c = nextc(p)) == '=') { - yylval.id = intern(">>",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern(">>",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tRSHFT; @@ -4151,9 +4172,9 @@ parser_yylex(parser_state *p) } if (p->lstate == EXPR_DOT) { if (cmd_state) - p->lstate = EXPR_CMDARG; + p->lstate = EXPR_CMDARG; else - p->lstate = EXPR_ARG; + p->lstate = EXPR_ARG; return '`'; } p->lex_strterm = new_strterm(p, str_xquote, '`', 0); @@ -4165,43 +4186,43 @@ parser_yylex(parser_state *p) return '?'; } c = nextc(p); - if (c == -1) { + if (c < 0) { yyerror(p, "incomplete character syntax"); return 0; } if (isspace(c)) { if (!IS_ARG()) { - int c2; - switch (c) { - case ' ': - c2 = 's'; - break; - case '\n': - c2 = 'n'; - break; - case '\t': - c2 = 't'; - break; - case '\v': - c2 = 'v'; - break; - case '\r': - c2 = 'r'; - break; - case '\f': - c2 = 'f'; - break; - default: - c2 = 0; - break; - } - if (c2) { - char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); - yyerror(p, buf); - } + int c2; + switch (c) { + case ' ': + c2 = 's'; + break; + case '\n': + c2 = 'n'; + break; + case '\t': + c2 = 't'; + break; + case '\v': + c2 = 'v'; + break; + case '\r': + c2 = 'r'; + break; + case '\f': + c2 = 'f'; + break; + default: + c2 = 0; + break; + } + if (c2) { + char buf[256]; + snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + yyerror(p, buf); + } } - ternary: + ternary: pushback(p, c); p->lstate = EXPR_VALUE; return '?'; @@ -4212,20 +4233,20 @@ parser_yylex(parser_state *p) int c2 = nextc(p); pushback(p, c2); if ((isalnum(c2) || c2 == '_')) { - goto ternary; + goto ternary; } } if (c == '\\') { c = nextc(p); if (c == 'u') { #if 0 - tokadd_utf8(p); + tokadd_utf8(p); #endif } else { - pushback(p, c); - c = read_escape(p); - tokadd(p, c); + pushback(p, c); + c = read_escape(p); + tokadd(p, c); } } else { @@ -4240,9 +4261,9 @@ parser_yylex(parser_state *p) if ((c = nextc(p)) == '&') { p->lstate = EXPR_BEG; if ((c = nextc(p)) == '=') { - yylval.id = intern("&&",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("&&",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tANDOP; @@ -4274,9 +4295,9 @@ parser_yylex(parser_state *p) if ((c = nextc(p)) == '|') { p->lstate = EXPR_BEG; if ((c = nextc(p)) == '=') { - yylval.id = intern("||",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("||",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tOROP; @@ -4300,7 +4321,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return tUPLUS; + return tUPLUS; } pushback(p, c); return '+'; @@ -4313,9 +4334,9 @@ parser_yylex(parser_state *p) if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { p->lstate = EXPR_BEG; pushback(p, c); - if (c != -1 && ISDIGIT(c)) { - c = '+'; - goto start_num; + if (c >= 0 && ISDIGIT(c)) { + c = '+'; + goto start_num; } return tUPLUS; } @@ -4328,7 +4349,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return tUMINUS; + return tUMINUS; } pushback(p, c); return '-'; @@ -4345,8 +4366,8 @@ parser_yylex(parser_state *p) if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { p->lstate = EXPR_BEG; pushback(p, c); - if (c != -1 && ISDIGIT(c)) { - return tUMINUS_NUM; + if (c >= 0 && ISDIGIT(c)) { + return tUMINUS_NUM; } return tUMINUS; } @@ -4358,244 +4379,244 @@ parser_yylex(parser_state *p) p->lstate = EXPR_BEG; if ((c = nextc(p)) == '.') { if ((c = nextc(p)) == '.') { - return tDOT3; + return tDOT3; } pushback(p, c); return tDOT2; } pushback(p, c); - if (c != -1 && ISDIGIT(c)) { + if (c >= 0 && ISDIGIT(c)) { yyerror(p, "no .<digit> floating literal anymore; put 0 before dot"); } p->lstate = EXPR_DOT; return '.'; - start_num: + start_num: case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - { - int is_float, seen_point, seen_e, nondigit; + { + int is_float, seen_point, seen_e, nondigit; - is_float = seen_point = seen_e = nondigit = 0; - p->lstate = EXPR_END; - token_column = newtok(p); - if (c == '-' || c == '+') { - tokadd(p, c); - c = nextc(p); - } - if (c == '0') { + is_float = seen_point = seen_e = nondigit = 0; + p->lstate = EXPR_END; + token_column = newtok(p); + if (c == '-' || c == '+') { + tokadd(p, c); + c = nextc(p); + } + if (c == '0') { #define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0) - int start = toklen(p); - c = nextc(p); - if (c == 'x' || c == 'X') { - /* hexadecimal */ - c = nextc(p); - if (c != -1 && ISXDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISXDIGIT(c)) break; - nondigit = 0; - tokadd(p, tolower(c)); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 16); - return tINTEGER; - } - if (c == 'b' || c == 'B') { - /* binary */ - c = nextc(p); - if (c == '0' || c == '1') { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c != '0' && c != '1') break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 2); - return tINTEGER; - } - if (c == 'd' || c == 'D') { - /* decimal */ - c = nextc(p); - if (c != -1 && ISDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISDIGIT(c)) break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; - } - if (c == '_') { - /* 0_0 */ - goto octal_number; - } - if (c == 'o' || c == 'O') { - /* prefixed octal */ - c = nextc(p); - if (c == -1 || c == '_' || !ISDIGIT(c)) { - no_digits(); - } - } - if (c >= '0' && c <= '7') { - /* octal */ - octal_number: - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c < '0' || c > '9') break; - if (c > '7') goto invalid_octal; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - - if (toklen(p) > start) { - pushback(p, c); - tokfix(p); - if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 8); - return tINTEGER; - } - if (nondigit) { - pushback(p, c); - goto trailing_uc; - } - } - if (c > '7' && c <= '9') { - invalid_octal: - yyerror(p, "Invalid octal digit"); - } - else if (c == '.' || c == 'e' || c == 'E') { - tokadd(p, '0'); - } - else { - pushback(p, c); - yylval.nd = new_int(p, "0", 10); - return tINTEGER; - } + int start = toklen(p); + c = nextc(p); + if (c == 'x' || c == 'X') { + /* hexadecimal */ + c = nextc(p); + if (c >= 0 && ISXDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISXDIGIT(c)) break; + nondigit = 0; + tokadd(p, tolower(c)); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 16); + return tINTEGER; + } + if (c == 'b' || c == 'B') { + /* binary */ + c = nextc(p); + if (c == '0' || c == '1') { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c != '0' && c != '1') break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 2); + return tINTEGER; + } + if (c == 'd' || c == 'D') { + /* decimal */ + c = nextc(p); + if (c >= 0 && ISDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISDIGIT(c)) break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; } + if (c == '_') { + /* 0_0 */ + goto octal_number; + } + if (c == 'o' || c == 'O') { + /* prefixed octal */ + c = nextc(p); + if (c < 0 || c == '_' || !ISDIGIT(c)) { + no_digits(); + } + } + if (c >= '0' && c <= '7') { + /* octal */ + octal_number: + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c < '0' || c > '9') break; + if (c > '7') goto invalid_octal; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + + if (toklen(p) > start) { + pushback(p, c); + tokfix(p); + if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 8); + return tINTEGER; + } + if (nondigit) { + pushback(p, c); + goto trailing_uc; + } + } + if (c > '7' && c <= '9') { + invalid_octal: + yyerror(p, "Invalid octal digit"); + } + else if (c == '.' || c == 'e' || c == 'E') { + tokadd(p, '0'); + } + else { + pushback(p, c); + yylval.nd = new_int(p, "0", 10); + return tINTEGER; + } + } - for (;;) { - switch (c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - nondigit = 0; - tokadd(p, c); - break; - - case '.': - if (nondigit) goto trailing_uc; - if (seen_point || seen_e) { - goto decode_num; - } - else { - int c0 = nextc(p); - if (c0 == -1 || !ISDIGIT(c0)) { - pushback(p, c0); - goto decode_num; - } - c = c0; - } - tokadd(p, '.'); - tokadd(p, c); - is_float++; - seen_point++; - nondigit = 0; - break; - - case 'e': - case 'E': - if (nondigit) { - pushback(p, c); - c = nondigit; - goto decode_num; - } - if (seen_e) { - goto decode_num; - } - tokadd(p, c); - seen_e++; - is_float++; - nondigit = c; - c = nextc(p); - if (c != '-' && c != '+') continue; - tokadd(p, c); - nondigit = c; - break; - - case '_': /* `_' in number just ignored */ - if (nondigit) goto decode_num; - nondigit = c; - break; - - default: - goto decode_num; - } - c = nextc(p); + for (;;) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + nondigit = 0; + tokadd(p, c); + break; + + case '.': + if (nondigit) goto trailing_uc; + if (seen_point || seen_e) { + goto decode_num; + } + else { + int c0 = nextc(p); + if (c0 < 0 || !ISDIGIT(c0)) { + pushback(p, c0); + goto decode_num; + } + c = c0; + } + tokadd(p, '.'); + tokadd(p, c); + is_float++; + seen_point++; + nondigit = 0; + break; + + case 'e': + case 'E': + if (nondigit) { + pushback(p, c); + c = nondigit; + goto decode_num; + } + if (seen_e) { + goto decode_num; + } + tokadd(p, c); + seen_e++; + is_float++; + nondigit = c; + c = nextc(p); + if (c != '-' && c != '+') continue; + tokadd(p, c); + nondigit = c; + break; + + case '_': /* `_' in number just ignored */ + if (nondigit) goto decode_num; + nondigit = c; + break; + + default: + goto decode_num; } + c = nextc(p); + } decode_num: - pushback(p, c); - if (nondigit) { + pushback(p, c); + if (nondigit) { trailing_uc: - yyerror_i(p, "trailing `%c' in number", nondigit); + yyerror_i(p, "trailing `%c' in number", nondigit); + } + tokfix(p); + if (is_float) { + double d; + char *endp; + + errno = 0; + d = strtod(tok(p), &endp); + if (d == 0 && endp == tok(p)) { + yywarning_s(p, "corrupted float value %s", tok(p)); } - tokfix(p); - if (is_float) { - double d; - char *endp; - - errno = 0; - d = strtod(tok(p), &endp); - if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); - } - else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); - errno = 0; - } - yylval.nd = new_float(p, tok(p)); - return tFLOAT; + else if (errno == ERANGE) { + yywarning_s(p, "float %s out of range", tok(p)); + errno = 0; } - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; + yylval.nd = new_float(p, tok(p)); + return tFLOAT; } + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } case ')': case ']': @@ -4613,8 +4634,8 @@ parser_yylex(parser_state *p) c = nextc(p); if (c == ':') { if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { - p->lstate = EXPR_BEG; - return tCOLON3; + p->lstate = EXPR_BEG; + return tCOLON3; } p->lstate = EXPR_DOT; return tCOLON2; @@ -4675,7 +4696,7 @@ parser_yylex(parser_state *p) case '~': if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { if ((c = nextc(p)) != '@') { - pushback(p, c); + pushback(p, c); } p->lstate = EXPR_ARG; } @@ -4702,11 +4723,11 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if ((c = nextc(p)) == ']') { - if ((c = nextc(p)) == '=') { - return tASET; - } - pushback(p, c); - return tAREF; + if ((c = nextc(p)) == '=') { + return tASET; + } + pushback(p, c); + return tAREF; } pushback(p, c); return '['; @@ -4759,21 +4780,21 @@ parser_yylex(parser_state *p) int paren; c = nextc(p); - quotation: - if (c == -1 || !ISALNUM(c)) { - term = c; - c = 'Q'; + quotation: + if (c < 0 || !ISALNUM(c)) { + term = c; + c = 'Q'; } else { - term = nextc(p); - if (isalnum(term)) { - yyerror(p, "unknown type of %string"); - return 0; - } + term = nextc(p); + if (isalnum(term)) { + yyerror(p, "unknown type of %string"); + return 0; + } } - if (c == -1 || term == -1) { - yyerror(p, "unterminated quoted string meets end of file"); - return 0; + if (c < 0 || term < 0) { + yyerror(p, "unterminated quoted string meets end of file"); + return 0; } paren = term; if (term == '(') term = ')'; @@ -4784,44 +4805,44 @@ parser_yylex(parser_state *p) switch (c) { case 'Q': - p->lex_strterm = new_strterm(p, str_dquote, term, paren); - return tSTRING_BEG; + p->lex_strterm = new_strterm(p, str_dquote, term, paren); + return tSTRING_BEG; case 'q': - p->lex_strterm = new_strterm(p, str_squote, term, paren); - return parse_string(p); + p->lex_strterm = new_strterm(p, str_squote, term, paren); + return parse_string(p); case 'W': - p->lex_strterm = new_strterm(p, str_dword, term, paren); - return tWORDS_BEG; + p->lex_strterm = new_strterm(p, str_dword, term, paren); + return tWORDS_BEG; case 'w': - p->lex_strterm = new_strterm(p, str_sword, term, paren); - return tWORDS_BEG; + p->lex_strterm = new_strterm(p, str_sword, term, paren); + return tWORDS_BEG; case 'x': - p->lex_strterm = new_strterm(p, str_xquote, term, paren); - return tXSTRING_BEG; + p->lex_strterm = new_strterm(p, str_xquote, term, paren); + return tXSTRING_BEG; case 'r': - p->lex_strterm = new_strterm(p, str_regexp, term, paren); - return tREGEXP_BEG; + p->lex_strterm = new_strterm(p, str_regexp, term, paren); + return tREGEXP_BEG; case 's': - p->lex_strterm = new_strterm(p, str_ssym, term, paren); - return tSYMBEG; + p->lex_strterm = new_strterm(p, str_ssym, term, paren); + return tSYMBEG; case 'I': - p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); - return tSYMBOLS_BEG; + p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); + return tSYMBOLS_BEG; case 'i': - p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); - return tSYMBOLS_BEG; + p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); + return tSYMBOLS_BEG; default: - yyerror(p, "unknown type of %string"); - return 0; + yyerror(p, "unknown type of %string"); + return 0; } } if ((c = nextc(p)) == '=') { @@ -4844,17 +4865,17 @@ parser_yylex(parser_state *p) p->lstate = EXPR_END; token_column = newtok(p); c = nextc(p); - if (c == -1) { + if (c < 0) { yyerror(p, "incomplete global variable syntax"); return 0; } switch (c) { case '_': /* $_: last read line string */ c = nextc(p); - if (c != -1 && identchar(c)) { /* if there is more after _ it is a variable */ - tokadd(p, '$'); - tokadd(p, c); - break; + if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ + tokadd(p, '$'); + tokadd(p, c); + break; } pushback(p, c); c = '_'; @@ -4886,7 +4907,7 @@ parser_yylex(parser_state *p) tokadd(p, c); c = nextc(p); pushback(p, c); - gvar: + gvar: tokfix(p); yylval.id = intern_cstr(tok(p)); return tGVAR; @@ -4896,9 +4917,9 @@ parser_yylex(parser_state *p) case '\'': /* $': string after last match */ case '+': /* $+: string matches last pattern */ if (last_state == EXPR_FNAME) { - tokadd(p, '$'); - tokadd(p, c); - goto gvar; + tokadd(p, '$'); + tokadd(p, c); + goto gvar; } yylval.nd = new_back_ref(p, c); return tBACK_REF; @@ -4907,9 +4928,9 @@ parser_yylex(parser_state *p) case '4': case '5': case '6': case '7': case '8': case '9': do { - tokadd(p, c); - c = nextc(p); - } while (c != -1 && isdigit(c)); + tokadd(p, c); + c = nextc(p); + } while (c >= 0 && isdigit(c)); pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); @@ -4918,58 +4939,58 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - pushback(p, c); - return '$'; + pushback(p, c); + return '$'; } case '0': tokadd(p, '$'); } break; - case '@': - c = nextc(p); - token_column = newtok(p); - tokadd(p, '@'); - if (c == '@') { - tokadd(p, '@'); + case '@': c = nextc(p); - } - if (c == -1) { - if (p->bidx == 1) { - yyerror(p, "incomplete instance variable syntax"); + token_column = newtok(p); + tokadd(p, '@'); + if (c == '@') { + tokadd(p, '@'); + c = nextc(p); } - else { - yyerror(p, "incomplete class variable syntax"); + if (c < 0) { + if (p->bidx == 1) { + yyerror(p, "incomplete instance variable syntax"); + } + else { + yyerror(p, "incomplete class variable syntax"); + } + return 0; } - return 0; - } - else if (isdigit(c)) { - if (p->bidx == 1) { - yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + else if (isdigit(c)) { + if (p->bidx == 1) { + yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + } + else { + yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + } + return 0; } - else { - yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + if (!identchar(c)) { + pushback(p, c); + return '@'; } - return 0; - } - if (!identchar(c)) { - pushback(p, c); - return '@'; - } - break; + break; - case '_': - token_column = newtok(p); - break; + case '_': + token_column = newtok(p); + break; - default: - if (!identchar(c)) { - yyerror_i(p, "Invalid char `\\x%02X' in expression", c); - goto retry; - } + default: + if (!identchar(c)) { + yyerror_i(p, "Invalid char `\\x%02X' in expression", c); + goto retry; + } - token_column = newtok(p); - break; + token_column = newtok(p); + break; } do { @@ -5006,95 +5027,95 @@ parser_yylex(parser_state *p) case '@': p->lstate = EXPR_END; if (tok(p)[1] == '@') - result = tCVAR; + result = tCVAR; else - result = tIVAR; + result = tIVAR; break; default: if (toklast(p) == '!' || toklast(p) == '?') { - result = tFID; + result = tFID; } else { - if (p->lstate == EXPR_FNAME) { - if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && - (!peek(p, '=') || (peek_n(p, '>', 1)))) { - result = tIDENTIFIER; - tokadd(p, c); - tokfix(p); - } - else { - pushback(p, c); - } - } - if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) { - result = tCONSTANT; - } - else { - result = tIDENTIFIER; - } + if (p->lstate == EXPR_FNAME) { + if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && + (!peek(p, '=') || (peek_n(p, '>', 1)))) { + result = tIDENTIFIER; + tokadd(p, c); + tokfix(p); + } + else { + pushback(p, c); + } + } + if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) { + result = tCONSTANT; + } + else { + result = tIDENTIFIER; + } } if (IS_LABEL_POSSIBLE()) { - if (IS_LABEL_SUFFIX(0)) { - p->lstate = EXPR_BEG; - nextc(p); - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tLABEL; - } + if (IS_LABEL_SUFFIX(0)) { + p->lstate = EXPR_BEG; + nextc(p); + tokfix(p); + yylval.id = intern_cstr(tok(p)); + return tLABEL; + } } if (p->lstate != EXPR_DOT) { - const struct kwtable *kw; - - /* See if it is a reserved word. */ - kw = mrb_reserved_word(tok(p), toklen(p)); - if (kw) { - enum mrb_lex_state_enum state = p->lstate; - p->lstate = kw->state; - if (state == EXPR_FNAME) { - yylval.id = intern_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]; - } - } + const struct kwtable *kw; + + /* See if it is a reserved word. */ + kw = mrb_reserved_word(tok(p), toklen(p)); + if (kw) { + enum mrb_lex_state_enum state = p->lstate; + p->lstate = kw->state; + if (state == EXPR_FNAME) { + yylval.id = intern_cstr(kw->name); + return kw->id[0]; + } + if (p->lstate == EXPR_BEG) { + p->cmd_start = TRUE; + } + if (kw->id[0] == keyword_do) { + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lpar_beg = 0; + p->paren_nest--; + return keyword_do_LAMBDA; + } + if (COND_P()) return keyword_do_cond; + if (CMDARG_P() && state != EXPR_CMDARG) + return keyword_do_block; + if (state == EXPR_ENDARG || state == EXPR_BEG) + return keyword_do_block; + return keyword_do; + } + if (state == EXPR_BEG || state == EXPR_VALUE) + return kw->id[0]; + else { + if (kw->id[0] != kw->id[1]) + p->lstate = EXPR_BEG; + return kw->id[1]; + } + } } if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) { - if (cmd_state) { - p->lstate = EXPR_CMDARG; - } - else { - p->lstate = EXPR_ARG; - } + if (cmd_state) { + p->lstate = EXPR_CMDARG; + } + else { + p->lstate = EXPR_ARG; + } } else if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; + p->lstate = EXPR_ENDFN; } else { - p->lstate = EXPR_END; + p->lstate = EXPR_END; } } { @@ -5103,7 +5124,7 @@ parser_yylex(parser_state *p) yylval.id = ident; #if 0 if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) { - p->lstate = EXPR_END; + p->lstate = EXPR_END; } #endif } @@ -5162,8 +5183,8 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) } } -void codedump_all(mrb_state*, struct RProc*); -void parser_dump(mrb_state *mrb, node *tree, int offset); +void mrb_codedump_all(mrb_state*, struct RProc*); +void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); void mrb_parser_parse(parser_state *p, mrbc_context *c) @@ -5187,7 +5208,7 @@ mrb_parser_parse(parser_state *p, mrbc_context *c) } parser_update_cxt(p, c); if (c && c->dump_result) { - parser_dump(p->mrb, p->tree, 0); + mrb_parser_dump(p->mrb, p->tree, 0); } } @@ -5286,7 +5307,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) sym = mrb_intern_cstr(p->mrb, f); p->filename = mrb_sym2name_len(p->mrb, sym, &len); 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; @@ -5364,7 +5385,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) int n; n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); + p->error_buffer[0].lineno, p->error_buffer[0].message); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); mrb_parser_free(p); return mrb_undef_value(); @@ -5384,7 +5405,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) return mrb_undef_value(); } if (c) { - if (c->dump_result) codedump_all(mrb, proc); + 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; @@ -5452,7 +5473,7 @@ static void dump_recur(mrb_state *mrb, node *tree, int offset) { while (tree) { - parser_dump(mrb, tree->car, offset); + mrb_parser_dump(mrb, tree->car, offset); tree = tree->cdr; } } @@ -5460,13 +5481,13 @@ dump_recur(mrb_state *mrb, node *tree, int offset) #endif void -parser_dump(mrb_state *mrb, node *tree, int offset) +mrb_parser_dump(mrb_state *mrb, node *tree, int offset) { #ifdef ENABLE_STDIO int n; if (!tree) return; - again: + again: dump_prefix(offset); n = (int)(intptr_t)tree->car; tree = tree->cdr; @@ -5481,7 +5502,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) if (tree->car) { dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); } tree = tree->cdr; if (tree->car) { @@ -5490,30 +5511,30 @@ parser_dump(mrb_state *mrb, node *tree, int offset) dump_prefix(offset+1); printf("rescue:\n"); while (n2) { - node *n3 = n2->car; - if (n3->car) { - dump_prefix(offset+2); - printf("handle classes:\n"); - dump_recur(mrb, n3->car, offset+3); - } - if (n3->cdr->car) { - dump_prefix(offset+2); - printf("exc_var:\n"); - parser_dump(mrb, n3->cdr->car, offset+3); - } - if (n3->cdr->cdr->car) { - dump_prefix(offset+2); - printf("rescue body:\n"); - parser_dump(mrb, n3->cdr->cdr->car, offset+3); - } - n2 = n2->cdr; + node *n3 = n2->car; + if (n3->car) { + dump_prefix(offset+2); + printf("handle classes:\n"); + dump_recur(mrb, n3->car, offset+3); + } + if (n3->cdr->car) { + dump_prefix(offset+2); + printf("exc_var:\n"); + mrb_parser_dump(mrb, n3->cdr->car, offset+3); + } + if (n3->cdr->cdr->car) { + dump_prefix(offset+2); + printf("rescue body:\n"); + mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); + } + n2 = n2->cdr; } } tree = tree->cdr; if (tree->car) { dump_prefix(offset+1); printf("else:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); } break; @@ -5521,10 +5542,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_ENSURE:\n"); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("ensure:\n"); - parser_dump(mrb, tree->cdr->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); break; case NODE_LAMBDA: @@ -5532,85 +5553,85 @@ parser_dump(mrb_state *mrb, node *tree, int offset) goto block; case NODE_BLOCK: - block: + block: printf("NODE_BLOCK:\n"); - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; - if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + if (n->car) { + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } } } - dump_prefix(offset+1); - printf("body:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); - break; + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } + } + dump_prefix(offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + break; case NODE_IF: printf("NODE_IF:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("then:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); if (tree->cdr->cdr->car) { dump_prefix(offset+1); printf("else:\n"); - parser_dump(mrb, tree->cdr->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); } break; case NODE_AND: printf("NODE_AND:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_OR: printf("NODE_OR:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_CASE: printf("NODE_CASE:\n"); if (tree->car) { - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); } tree = tree->cdr; while (tree) { @@ -5619,7 +5640,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, tree->car->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; } break; @@ -5628,20 +5649,20 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_WHILE:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_UNTIL: printf("NODE_UNTIL:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_FOR: @@ -5652,35 +5673,35 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); + dump_prefix(offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("rest:\n"); - parser_dump(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } + if (n2->car) { + dump_prefix(offset+2); + printf("rest:\n"); + mrb_parser_dump(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } } } tree = tree->cdr; dump_prefix(offset+1); printf("in:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(offset+1); printf("do:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); break; case NODE_SCOPE: @@ -5689,17 +5710,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); - printf("local variables:\n"); - dump_prefix(offset+2); - while (n2) { - if (n2->car) { - if (n2 != tree->car) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - } - n2 = n2->cdr; - } - printf("\n"); + dump_prefix(offset+1); + printf("local variables:\n"); + dump_prefix(offset+2); + while (n2) { + if (n2->car) { + if (n2 != tree->car) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + } + n2 = n2->cdr; + } + printf("\n"); } } tree = tree->cdr; @@ -5709,39 +5730,39 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_FCALL: case NODE_CALL: printf("NODE_CALL:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("method='%s' (%d)\n", - mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); + mrb_sym2name(mrb, sym(tree->cdr->car)), + (int)(intptr_t)tree->cdr->car); tree = tree->cdr->cdr->car; if (tree) { dump_prefix(offset+1); printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); - printf("block:\n"); - parser_dump(mrb, tree->cdr, offset+2); + dump_prefix(offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); } } break; case NODE_DOT2: printf("NODE_DOT2:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_DOT3: printf("NODE_DOT3:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_COLON2: printf("NODE_COLON2:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); break; @@ -5762,27 +5783,27 @@ parser_dump(mrb_state *mrb, node *tree, int offset) while (tree) { dump_prefix(offset+1); printf("key:\n"); - parser_dump(mrb, tree->car->car, offset+2); + mrb_parser_dump(mrb, tree->car->car, offset+2); dump_prefix(offset+1); printf("value:\n"); - parser_dump(mrb, tree->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; } break; case NODE_SPLAT: printf("NODE_SPLAT:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_ASGN: printf("NODE_ASGN:\n"); dump_prefix(offset+1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_MASGN: @@ -5793,48 +5814,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); + dump_prefix(offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("rest:\n"); - if (n2->car == (node*)-1) { - dump_prefix(offset+2); - printf("(empty)\n"); - } - else { - parser_dump(mrb, n2->car, offset+3); - } - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } + if (n2->car) { + dump_prefix(offset+2); + printf("rest:\n"); + if (n2->car == (node*)-1) { + dump_prefix(offset+2); + printf("(empty)\n"); + } + else { + mrb_parser_dump(mrb, n2->car, offset+3); + } + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } } } dump_prefix(offset+1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_OP_ASGN: printf("NODE_OP_ASGN:\n"); dump_prefix(offset+1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(offset+1); printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); tree = tree->cdr; - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); break; case NODE_SUPER: @@ -5844,9 +5865,9 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); - printf("block:\n"); - parser_dump(mrb, tree->cdr, offset+2); + dump_prefix(offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); } } break; @@ -5857,7 +5878,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_RETURN: printf("NODE_RETURN:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_YIELD: @@ -5867,12 +5888,12 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_BREAK: printf("NODE_BREAK:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_NEXT: printf("NODE_NEXT:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_REDO: @@ -5907,10 +5928,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_MATCH:\n"); dump_prefix(offset + 1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset + 2); + mrb_parser_dump(mrb, tree->car, offset + 2); dump_prefix(offset + 1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset + 2); + mrb_parser_dump(mrb, tree->cdr, offset + 2); break; case NODE_BACK_REF: @@ -5927,7 +5948,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_BLOCK_ARG: printf("NODE_BLOCK_ARG:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_INT: @@ -5940,7 +5961,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_NEGATE: printf("NODE_NEGATE\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_STR: @@ -5996,8 +6017,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_ALIAS: printf("NODE_ALIAS %s %s:\n", - mrb_sym2name(mrb, sym(tree->car)), - mrb_sym2name(mrb, sym(tree->cdr))); + mrb_sym2name(mrb, sym(tree->car)), + mrb_sym2name(mrb, sym(tree->cdr))); break; case NODE_UNDEF: @@ -6005,8 +6026,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset) { node *t = tree; while (t) { - printf(" %s", mrb_sym2name(mrb, sym(t->car))); - t = t->cdr; + printf(" %s", mrb_sym2name(mrb, sym(t->car))); + t = t->cdr; } } printf(":\n"); @@ -6023,18 +6044,18 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { - parser_dump(mrb, tree->car->car, offset+1); + mrb_parser_dump(mrb, tree->car->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } if (tree->cdr->car) { dump_prefix(offset+1); printf("super:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); } dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); break; case NODE_MODULE: @@ -6048,21 +6069,21 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { - parser_dump(mrb, tree->car->car, offset+1); + mrb_parser_dump(mrb, tree->car->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; case NODE_SCLASS: printf("NODE_SCLASS:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; case NODE_DEF: @@ -6074,17 +6095,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); - printf("local variables:\n"); - dump_prefix(offset+2); - while (n2) { - if (n2->car) { - if (n2 != tree->car) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - } - n2 = n2->cdr; - } - printf("\n"); + dump_prefix(offset+1); + printf("local variables:\n"); + dump_prefix(offset+2); + while (n2) { + if (n2->car) { + if (n2 != tree->car) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + } + n2 = n2->cdr; + } + printf("\n"); } } tree = tree->cdr; @@ -6092,48 +6113,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n = tree->car; if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); } } - parser_dump(mrb, tree->cdr->car, offset+1); + mrb_parser_dump(mrb, tree->cdr->car, offset+1); break; case NODE_SDEF: printf("NODE_SDEF:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); tree = tree->cdr; dump_prefix(offset+1); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); @@ -6142,54 +6163,54 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n = tree->car; if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); } } tree = tree->cdr; - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); break; case NODE_POSTEXE: printf("NODE_POSTEXE:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_HEREDOC: printf("NODE_HEREDOC:\n"); - parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); + mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; default: diff --git a/src/print.c b/src/print.c index 01c9b3cd0..94250ddce 100644 --- a/src/print.c +++ b/src/print.c @@ -6,6 +6,7 @@ #include "mruby.h" #include "mruby/string.h" +#include "mruby/variable.h" static void printstr(mrb_state *mrb, mrb_value obj) @@ -53,19 +54,31 @@ mrb_print_error(mrb_state *mrb) void mrb_show_version(mrb_state *mrb) { - static const char version_msg[] = "mruby - Embeddable Ruby Copyright (c) 2010-2013 mruby developers\n"; + static const char version_msg[] = "mruby - Embeddable Ruby Copyright (c) 2010-2014 mruby developers\n"; mrb_value msg; - msg = mrb_str_new(mrb, version_msg, sizeof(version_msg) - 1); + if (mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION"))) { + msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION")); + msg = mrb_funcall(mrb, msg, "+", 1, mrb_str_new_lit(mrb, "\n")); + } + else { + msg = mrb_str_new_lit(mrb, version_msg); + } printstr(mrb, msg); } void mrb_show_copyright(mrb_state *mrb) { - static const char copyright_msg[] = "mruby - Copyright (c) 2010-2013 mruby developers\n"; + static const char copyright_msg[] = "mruby - Copyright (c) 2010-2014 mruby developers\n"; mrb_value msg; - msg = mrb_str_new(mrb, copyright_msg, sizeof(copyright_msg) - 1); + if (mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT"))) { + msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")); + msg = mrb_funcall(mrb, msg, "+", 1, mrb_str_new_lit(mrb, "\n")); + } + else { + msg = mrb_str_new_lit(mrb, copyright_msg); + } printstr(mrb, msg); } diff --git a/src/proc.c b/src/proc.c index b2bbe2453..1ae1d495e 100644 --- a/src/proc.c +++ b/src/proc.c @@ -17,9 +17,16 @@ struct RProc * mrb_proc_new(mrb_state *mrb, mrb_irep *irep) { struct RProc *p; + mrb_callinfo *ci = mrb->c->ci; p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - p->target_class = (mrb->c->ci) ? mrb->c->ci->target_class : 0; + p->target_class = 0; + if (ci) { + if (ci->proc) + p->target_class = ci->proc->target_class; + if (!p->target_class) + p->target_class = ci->target_class; + } p->body.irep = irep; p->env = 0; mrb_irep_incref(mrb, irep); diff --git a/src/range.c b/src/range.c index 0eacc83d5..7b3807865 100644 --- a/src/range.c +++ b/src/range.c @@ -376,7 +376,7 @@ range_eql(mrb_state *mrb, mrb_value range) } /* 15.2.14.4.15(x) */ -mrb_value +static mrb_value range_initialize_copy(mrb_state *mrb, mrb_value copy) { mrb_value src; diff --git a/src/state.c b/src/state.c index f25d8c8bf..620ed7d77 100644 --- a/src/state.c +++ b/src/state.c @@ -7,7 +7,6 @@ #include <stdlib.h> #include <string.h> #include "mruby.h" -#include "mruby/class.h" #include "mruby/irep.h" #include "mruby/variable.h" #include "mruby/debug.h" @@ -20,7 +19,7 @@ void mrb_final_core(mrb_state*); static mrb_value inspect_main(mrb_state *mrb, mrb_value mod) { - return mrb_str_new(mrb, "main", 4); + return mrb_str_new_lit(mrb, "main"); } mrb_state* diff --git a/src/string.c b/src/string.c index e8c37180d..96a625802 100644 --- a/src/string.c +++ b/src/string.c @@ -107,16 +107,6 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) return str; } -static inline void -str_mod_check(mrb_state *mrb, mrb_value str, char *p, mrb_int len) -{ - struct RString *s = mrb_str_ptr(str); - - if (s->ptr != p || s->len != len) { - mrb_raise(mrb, E_RUNTIME_ERROR, "string modified"); - } -} - #define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) /* char offset to byte offset */ @@ -142,7 +132,7 @@ str_new(mrb_state *mrb, const char *p, mrb_int len) return s; } -void +static void str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; @@ -751,12 +741,10 @@ num_index: /* check if indx is Range */ { mrb_int beg, len; - mrb_value tmp; len = RSTRING_LEN(str); if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { - tmp = mrb_str_subseq(mrb, str, beg, len); - return tmp; + return mrb_str_subseq(mrb, str, beg, len); } else { return mrb_nil_value(); @@ -2422,7 +2410,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) p = RSTRING_PTR(str); pend = RSTRING_END(str); for (;p < pend; p++) { - unsigned int c, cc; + unsigned char c, cc; c = *p; if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) { diff --git a/src/symbol.c b/src/symbol.c index 4e78ade66..4d6a8eb7a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -5,7 +5,6 @@ */ #include <ctype.h> -#include <limits.h> #include <string.h> #include "mruby.h" #include "mruby/khash.h" diff --git a/src/variable.c b/src/variable.c index c66e7fe89..5ced2dfbd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -4,14 +4,12 @@ ** See Copyright Notice in mruby.h */ +#include <ctype.h> #include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/proc.h" #include "mruby/string.h" -#include "mruby/variable.h" -#include "error.h" -#include <ctype.h> typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); @@ -756,7 +754,7 @@ mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) } void -mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v) +mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) { struct RClass * cls = c; @@ -823,24 +821,7 @@ mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) struct RClass *c = mrb->c->ci->proc->target_class; if (!c) c = mrb->c->ci->target_class; - while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } - } - c = c->super; - } - c = mrb->c->ci->target_class; - if (!c->iv) { - c->iv = iv_new(mrb); - } - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, c->iv, sym, v); + mrb_mod_cv_set(mrb, c, sym, v); } mrb_bool @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <string.h> #include <setjmp.h> #include <stddef.h> #include <stdarg.h> @@ -13,7 +12,6 @@ #include "mruby/class.h" #include "mruby/hash.h" #include "mruby/irep.h" -#include "mruby/numeric.h" #include "mruby/proc.h" #include "mruby/range.h" #include "mruby/string.h" @@ -231,6 +229,7 @@ cipush(mrb_state *mrb) ci->ridx = ridx; ci->env = 0; ci->pc = 0; + ci->err = 0; return ci; } @@ -263,6 +262,8 @@ ecall(mrb_state *mrb, int i) p = mrb->c->ensure[i]; if (!p) return; + if (mrb->c->ci->eidx > i) + mrb->c->ci->eidx = i; ci = cipush(mrb); ci->stackidx = mrb->c->stack - mrb->c->stbase; ci->mid = ci[-1].mid; @@ -601,7 +602,6 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_init(mrb); } stack_extend(mrb, irep->nregs, stack_keep); - mrb->c->ci->err = pc; mrb->c->ci->proc = proc; mrb->c->ci->nregs = irep->nregs + 1; regs = mrb->c->stack; @@ -852,13 +852,14 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int CASE(OP_EPOP) { /* A A.times{ensure_pop().call} */ - int n; int a = GETARG_A(i); + mrb_callinfo *ci = mrb->c->ci; + int n, eidx = ci->eidx; - for (n=0; n<a; n++) { - ecall(mrb, --mrb->c->ci->eidx); + for (n=0; n<a && eidx > ci[-1].eidx; n++) { + ecall(mrb, --eidx); + ARENA_RESTORE(mrb, ai); } - ARENA_RESTORE(mrb, ai); NEXT; } @@ -1349,7 +1350,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int ci = mrb->c->ci; break; case OP_R_BREAK: - if (proc->env->cioff < 0) { + if (!proc->env || proc->env->cioff < 0) { localjump_error(mrb, LOCALJUMP_ERROR_BREAK); goto L_RAISE; } @@ -2112,11 +2113,15 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int CASE(OP_DEBUG) { /* A debug print R(A),R(B),R(C) */ +#ifdef ENABLE_DEBUG + mrb->debug_op_hook(mrb, irep, pc, regs); +#else #ifdef ENABLE_STDIO printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); #else abort(); #endif +#endif NEXT; } @@ -2130,7 +2135,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int ecall(mrb, n); } } - mrb->c->ci->err = 0; + ERR_PC_CLR(mrb); mrb->jmp = prev_jmp; if (mrb->exc) { return mrb_obj_value(mrb->exc); diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index 70c44ed5e..e9caf1d3a 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -149,7 +149,7 @@ module MRuby end end # generate_gem_init - def print_gem_init_header(f) + def print_gem_comment(f) f.puts %Q[/*] f.puts %Q[ * This file is loading the irep] f.puts %Q[ * Ruby GEM code.] @@ -158,15 +158,23 @@ module MRuby f.puts %Q[ * This file was generated!] f.puts %Q[ * All manual changes will get lost.] f.puts %Q[ */] + end + + def print_gem_init_header(f) + print_gem_comment(f) + f.puts %Q[#include <stdlib.h>] unless rbfiles.empty? + f.puts %Q[#include "mruby.h"] + f.puts %Q[#include "mruby/irep.h"] unless rbfiles.empty? + end + + def print_gem_test_header(f) + print_gem_comment(f) f.puts %Q[#include <stdlib.h>] f.puts %Q[#include "mruby.h"] + f.puts %Q[#include "mruby/array.h"] f.puts %Q[#include "mruby/irep.h"] - f.puts %Q[#include "mruby/dump.h"] f.puts %Q[#include "mruby/string.h"] - f.puts %Q[#include "mruby/proc.h"] f.puts %Q[#include "mruby/variable.h"] - f.puts %Q[#include "mruby/array.h"] - f.puts %Q[#include "mruby/hash.h"] end def version_ok?(req_versions) diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake index 500161103..36c8e84b7 100644 --- a/tasks/mrbgems_test.rake +++ b/tasks/mrbgems_test.rake @@ -3,9 +3,9 @@ MRuby.each_target do test_rbobj = g.test_rbireps.ext(exts.object) file test_rbobj => g.test_rbireps - file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile, libfile("#{build_dir}/lib/libmruby")] do |t| + file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile] do |t| open(t.name, 'w') do |f| - g.print_gem_init_header(f) + g.print_gem_test_header(f) test_preload = [g.dir, MRUBY_ROOT].map {|dir| File.expand_path(g.test_preload, dir) }.find {|file| File.exist?(file) } diff --git a/test/init_mrbtest.c b/test/init_mrbtest.c index 3b8f9129e..8d01624f0 100644 --- a/test/init_mrbtest.c +++ b/test/init_mrbtest.c @@ -1,9 +1,6 @@ #include <stdlib.h> #include "mruby.h" #include "mruby/irep.h" -#include "mruby/dump.h" -#include "mruby/string.h" -#include "mruby/proc.h" extern const uint8_t mrbtest_irep[]; diff --git a/test/t/array.rb b/test/t/array.rb index 8ef1eee3f..1398bdc6e 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -49,6 +49,11 @@ assert('Array#[]', '15.2.12.5.4') do assert_equal(nil, [1,2,3].[](4)) assert_equal(3, [1,2,3].[](-1)) assert_equal(nil, [1,2,3].[](-4)) + + a = [ "a", "b", "c", "d", "e" ] + a[1.1] == "b" and + a[1,2] == ["b", "c"] and + a[1..-2] == ["b", "c", "d"] end assert('Array#[]=', '15.2.12.5.5') do @@ -64,6 +69,18 @@ assert('Array#[]=', '15.2.12.5.5') do assert_equal(4, [1,2,3].[]=(1,4)) assert_equal(3, [1,2,3].[]=(1,2,3)) + + a = [1,2,3,4,5] + a[3..-1] = 6 + assert_equal([1,2,3,6], a) + + a = [1,2,3,4,5] + a[3..-1] = [] + assert_equal([1,2,3], a) + + a = [1,2,3,4,5] + a[2...4] = 6 + assert_equal([1,2,6,5], a) end assert('Array#clear', '15.2.12.5.6') do @@ -301,6 +318,7 @@ assert('Array#hash', '15.2.12.5.35') do a = [ 1, 2, 3 ] assert_true(a.hash.is_a? Integer) + assert_equal([1,2].hash, [1,2].hash) end assert('Array#<=>', '15.2.12.5.36') do @@ -328,6 +346,3 @@ assert("Array (Longish inline array)") do ary.each {|p| h[p.class] += 1} assert_equal({Array=>200}, h) end - - - diff --git a/test/t/class.rb b/test/t/class.rb index a6ba336e3..bea20ee24 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -359,3 +359,13 @@ assert('singleton tests') do end end end + +assert('clone Class') do + class Foo + def func + true + end + end + + Foo.clone.new.func +end diff --git a/test/t/exception.rb b/test/t/exception.rb index 4239cba8b..8099e911f 100644 --- a/test/t/exception.rb +++ b/test/t/exception.rb @@ -345,3 +345,15 @@ assert('Exception#backtrace') do true end + +assert('Raise in ensure') do + + assert_raise(RuntimeError) do + begin + raise "" + ensure + raise "" + end + end + +end diff --git a/test/t/float.rb b/test/t/float.rb index f70bf2d66..0c67f510a 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -143,3 +143,10 @@ assert('Float#truncate', '15.2.9.3.15') do assert_equal( 3, 3.123456789.truncate) assert_equal(-3, -3.1.truncate) end + +assert('Float#nan?') do + assert_true (0.0/0.0).nan? + assert_false 0.0.nan? + assert_false (1.0/0.0).nan? + assert_false (-1.0/0.0).nan? +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index a78bfe35f..e7c9c2635 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -388,7 +388,15 @@ assert('Kernel#object_id', '15.3.1.3.33') do a = "" b = "" assert_not_equal a.object_id, b.object_id - assert_not_equal 1.object_id, 1.2.object_id + + assert_kind_of Numeric, object_id + assert_kind_of Numeric, "".object_id + assert_kind_of Numeric, true.object_id + assert_kind_of Numeric, false.object_id + assert_kind_of Numeric, nil.object_id + assert_kind_of Numeric, :no.object_id + assert_kind_of Numeric, 1.object_id + assert_kind_of Numeric, 1.0.object_id end # Kernel#p is defined in mruby-print mrbgem. '15.3.1.3.34' @@ -471,6 +479,27 @@ assert('Kernel#!=') do assert_false (str2 != str1) end +# operator "!~" is defined in ISO Ruby 11.4.4. +assert('Kernel#!~') do + x = "x" + def x.=~(other) + other == "x" + end + assert_false x !~ "x" + assert_true x !~ "z" + + y = "y" + def y.=~(other) + other == "y" + end + def y.!~(other) + other == "not y" + end + assert_false y !~ "y" + assert_false y !~ "z" + assert_true y !~ "not y" +end + assert('Kernel#respond_to_missing?') do class Test4RespondToMissing def respond_to_missing?(method_name, include_private = false) diff --git a/test/t/localjumperror.rb b/test/t/localjumperror.rb index a7d18b3b1..1780cb518 100644 --- a/test/t/localjumperror.rb +++ b/test/t/localjumperror.rb @@ -3,10 +3,10 @@ assert('LocalJumpError', '15.2.25') do assert_equal Class, LocalJumpError.class - assert_raise LocalJumpError do - # this will cause an exception due to the wrong location - retry - end +# assert_raise LocalJumpError do +# # this will cause an exception due to the wrong location +# retry +# end end # TODO 15.2.25.2.1 LocalJumpError#exit_value diff --git a/test/t/module.rb b/test/t/module.rb index 170eb925a..48a09f720 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -503,3 +503,17 @@ assert('Issue 1467') do C1.new C2.new end + +assert('clone Module') do + module M1 + def foo + true + end + end + + class B + include M1.clone + end + + B.new.foo +end diff --git a/test/t/string.rb b/test/t/string.rb index 4c3689b3a..c42fa006f 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -28,6 +28,8 @@ assert('String#==', '15.2.10.5.2') do assert_not_equal 'abc', 'cba' end +# 'String#=~', '15.2.10.5.3' will be tested in mrbgems. + assert('String#+', '15.2.10.5.4') do assert_equal 'ab', 'a' + 'b' end @@ -36,8 +38,6 @@ assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 end -# 'String#=~', '15.2.10.5.5' will be tested in mrbgems. - assert('String#[]', '15.2.10.5.6') do # length of args is 1 a = 'abc'[0] diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 4ddbefea3..13cd1198e 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -42,6 +42,98 @@ assert('Abbreviated variable assignment', '11.4.2.3.2') do assert_equal 3, c end +assert('case expression', '11.5.2.2.4') do + # case-expression-with-expression, one when-clause + x = 0 + case "a" + when "a" + x = 1 + end + assert_equal 1, x + + # case-expression-with-expression, multiple when-clauses + x = 0 + case "b" + when "a" + x = 1 + when "b" + x = 2 + end + assert_equal 2, x + + # no matching when-clause + x = 0 + case "c" + when "a" + x = 1 + when "b" + x = 2 + end + assert_equal 0, x + + # case-expression-with-expression, one when-clause and one else-clause + a = 0 + case "c" + when "a" + x = 1 + else + x = 3 + end + assert_equal 3, x + + # case-expression-without-expression, one when-clause + x = 0 + case + when true + x = 1 + end + assert_equal 1, x + + # case-expression-without-expression, multiple when-clauses + x = 0 + case + when 0 == 1 + x = 1 + when 1 == 1 + x = 2 + end + assert_equal 2, x + + # case-expression-without-expression, one when-clause and one else-clause + x = 0 + case + when 0 == 1 + x = 1 + else + x = 3 + end + assert_equal 3, x + + # multiple when-arguments + x = 0 + case 4 + when 1, 3, 5 + x = 1 + when 2, 4, 6 + x = 2 + end + assert_equal 2, x + + # when-argument with splatting argument + x = :integer + odds = [ 1, 3, 5, 7, 9 ] + evens = [ 2, 4, 6, 8 ] + case 5 + when *odds + x = :odd + when *evens + x = :even + end + assert_equal :odd, x + + true +end + assert('Nested const reference') do module Syntax4Const CONST1 = "hello world" @@ -102,3 +194,26 @@ assert('Return values of case statements') do assert_equal [nil], b assert_equal 1, fb.call end + +assert('splat in case statement') do + values = [3,5,1,7,8] + testa = [1,2,7] + testb = [5,6] + resulta = [] + resultb = [] + resultc = [] + values.each do |value| + case value + when *testa + resulta << value + when *testb + resultb << value + else + resultc << value + end + end + + assert_equal [1,7], resulta + assert_equal [5], resultb + assert_equal [3,8], resultc +end |
