From 9da4f78db46764be6dae5e7e83ff48cbecb3fb23 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 12 May 2000 09:07:57 +0000 Subject: [PATCH] 2000-05-12 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@687 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 55 +- MANIFEST | 1 - ToDo | 2 + array.c | 1 - bignum.c | 3 +- configure | 1 - configure.in | 1 - dln.c | 1 + eval.c | 18 +- ext/etc/etc.c | 5 + ext/md5/depend | 2 +- ext/socket/socket.c | 20 +- ext/socket/sockport.h | 2 +- file.c | 9 + gc.c | 7 +- hash.c | 4 - intern.h | 8 + io.c | 49 +- lib/irb/completion.rb | 47 ++ lib/irb/frame.rb | 67 +++ lib/irb/input-method.rb | 118 ++++ lib/irb/loader.rb | 118 ++++ lib/irb/main.rb | 867 ++++++++++++++++++++++++++++++ lib/irb/multi-irb.rb | 212 ++++++++ lib/irb/ruby-lex.rb | 955 +++++++++++++++++++++++++++++++++ lib/irb/ruby-token.rb | 266 +++++++++ lib/irb/slex.rb | 279 ++++++++++ lib/irb/version.rb | 16 + lib/irb/workspace-binding-2.rb | 15 + lib/irb/workspace-binding.rb | 77 +++ lib/irb/xmp.rb | 84 +++ lib/matrix.rb | 1 - lib/thread.rb | 9 +- marshal.c | 2 - pack.c | 78 +++ parse.y | 137 +++-- regex.c | 41 +- ruby.c | 16 +- ruby.h | 12 +- sample/irb.rb | 28 + sample/rbc.rb | 2 +- string.c | 4 +- time.c | 6 - util.c | 22 - variable.c | 3 - version.h | 8 +- 46 files changed, 3491 insertions(+), 188 deletions(-) create mode 100644 lib/irb/completion.rb create mode 100644 lib/irb/frame.rb create mode 100644 lib/irb/input-method.rb create mode 100644 lib/irb/loader.rb create mode 100644 lib/irb/main.rb create mode 100644 lib/irb/multi-irb.rb create mode 100644 lib/irb/ruby-lex.rb create mode 100644 lib/irb/ruby-token.rb create mode 100644 lib/irb/slex.rb create mode 100644 lib/irb/version.rb create mode 100644 lib/irb/workspace-binding-2.rb create mode 100644 lib/irb/workspace-binding.rb create mode 100644 lib/irb/xmp.rb create mode 100644 sample/irb.rb diff --git a/ChangeLog b/ChangeLog index 07fa720ced..15c28a9e42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,57 @@ -Tue May 9 17:08:43 2000 Yukihiro Matsumoto +Fri May 12 17:33:44 2000 Yukihiro Matsumoto - * array.c (Init_Array): prepare 'append' as alias to `push'. + * regex.c (re_compile_pattern): charset_not should not exclude + newline from matching set. + +Thu May 11 22:51:05 2000 Ryunosuke Ohshima + + * pack.c (pack_pack): Bignum support. + + * pack.c (pack_unpack): ditto. + +Thu May 11 21:19:29 2000 Hiroshi Igarashi + + * intern.h: add missing declarations of ruby API functions. + + * ruby.h: fix function name in declarations. + +Thu May 11 22:29:25 2000 Katsuyuki Komatsu + + * ext/md5/depend: add $(topdir)/config.h dependency to md5c.o. + + * ext/md5/extconf.rb: new file to add -DHAVE_CONFIG_H flag for Alpha. + +Thu May 11 10:55:52 2000 Ryunosuke Ohshima + + * pack.c (pack_pack): packing BER compressed integer by `w'. + + * pack.c (pack_unpack): unpacking BER. + +Thu May 11 00:37:55 2000 Yukihiro Matsumoto + + * parse.y (parse_regx): remove in_brack. + +Wed May 10 12:51:18 2000 Yukihiro Matsumoto + + * ruby.c (proc_options): move adding RUBYLIB and "." to the load + path after #! line parsing. + + * parse.y (parse_regx): should parse backslash escape like `\c[' + here to avoid causing `unterminated regexp' error. + +Wed May 10 00:19:53 2000 Katsuyuki Komatsu + + * MANIFEST, beos/GNUmakefile.in, configure.in: no longer need + beos/GNUmakefile.in to support BeOS R4.5.2 (Intel) as a result + of eban's Makefile.in change. + + * io.c: NOFILE is already defined on BeOS R4.5 (Intel) or later. + + * lib/matrix.rb: remove debug print. + + * regex.c: don't use nested comment. + +Tue May 9 17:08:43 2000 Yukihiro Matsumoto * eval.c (massign): no longer convert nil into empty array. diff --git a/MANIFEST b/MANIFEST index b30efedcb2..c2f0dd1e12 100644 --- a/MANIFEST +++ b/MANIFEST @@ -75,7 +75,6 @@ util.c variable.c version.c version.h -beos/GNUmakefile.in cygwin/GNUmakefile.in ext/Setup ext/Setup.dj diff --git a/ToDo b/ToDo index 9e49c4ba9e..84d0ea128a 100644 --- a/ToDo +++ b/ToDo @@ -41,6 +41,7 @@ Hacking Interpreter * scrambled script, or script filter * setuid ruby * performance tune for in-block (dynamic) local variables. +* generational GC ?? (is it possible?) Standard Libraries @@ -64,6 +65,7 @@ Standard Libraries - Kernel#scan - call initialize for builtin classes too (not yet: Regexp, Class, Module) - performance tune for String's non-bang methods. +- 'w' template for pack/unpack * String#scanf(?) * Object#fmt(?) * Integer#{bin,oct,hex,heX} diff --git a/array.c b/array.c index 7b5ec47830..6793fdde88 100644 --- a/array.c +++ b/array.c @@ -1601,7 +1601,6 @@ Init_Array() rb_define_method(rb_cArray, "last", rb_ary_last, 0); rb_define_method(rb_cArray, "concat", rb_ary_concat, 1); rb_define_method(rb_cArray, "<<", rb_ary_push, 1); - rb_define_method(rb_cArray, "append", rb_ary_push_m, -1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); rb_define_method(rb_cArray, "pop", rb_ary_pop, 0); rb_define_method(rb_cArray, "shift", rb_ary_shift, 0); diff --git a/bignum.c b/bignum.c index f9dc5fe611..8fb3d39406 100644 --- a/bignum.c +++ b/bignum.c @@ -423,6 +423,7 @@ rb_big2ulong(x) unsigned long num = big2ulong(x, "unsigned long"); if (!RBIGNUM(x)->sign) return -num; + return num; } long @@ -944,7 +945,7 @@ rb_big_remainder(x, y) return rb_big_modulo(x, y, 0); } -static VALUE +VALUE rb_big_divmod(x, y) VALUE x, y; { diff --git a/configure b/configure index ec6b66fb1f..e2fdcd92fa 100644 --- a/configure +++ b/configure @@ -4870,7 +4870,6 @@ if test "$target_os" = "beos"; then ;; i586*) LDFLAGS="$LDFLAGS -L." - FIRSTMAKEFILE=GNUmakefile:beos/GNUmakefile.in ;; *) echo EXPORTS > ruby.def diff --git a/configure.in b/configure.in index c83b0ab74c..22e1e68dce 100644 --- a/configure.in +++ b/configure.in @@ -707,7 +707,6 @@ if test "$target_os" = "beos"; then ;; i586*) LDFLAGS="$LDFLAGS -L." - FIRSTMAKEFILE=GNUmakefile:beos/GNUmakefile.in ;; *) echo EXPORTS > ruby.def diff --git a/dln.c b/dln.c index 3a02dbf996..be0aca4353 100644 --- a/dln.c +++ b/dln.c @@ -15,6 +15,7 @@ #include "dln.h" char *dln_argv0; +void rb_loaderror(); #ifdef _AIX #pragma alloca diff --git a/eval.c b/eval.c index 730b82e59a..7466e587df 100644 --- a/eval.c +++ b/eval.c @@ -1362,7 +1362,6 @@ ev_const_set(cref, id, val) VALUE val; { NODE *cbase = cref; - VALUE tmp; while (cbase && cbase->nd_clss != rb_cObject) { struct RClass *klass = RCLASS(cbase->nd_clss); @@ -2760,9 +2759,12 @@ rb_eval(self, n) else if (SCOPE_TEST(SCOPE_PROTECTED)) { noex = NOEX_PROTECTED; } - else { + else if (ruby_class == rb_cObject) { noex = node->nd_noex; } + else { + noex = NOEX_PUBLIC; + } if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) { noex |= NOEX_UNDEF; } @@ -4552,7 +4554,7 @@ rb_f_eval(argc, argv, self) VALUE *argv; VALUE self; { - VALUE src, scope, vfile, vline, val; + VALUE src, scope, vfile, vline; char *file = "(eval)"; int line = 1; @@ -4660,7 +4662,7 @@ yield_under_i(self) if (ruby_block->flags & BLOCK_DYNAMIC) { struct BLOCK * volatile old_block = ruby_block; struct BLOCK block; - volatile VALUE cbase = ruby_block->frame.cbase; + /* cbase should be pointed from volatile local variable */ /* to be protected from GC. */ VALUE result; @@ -4977,9 +4979,8 @@ rb_f_require(obj, fname) buf = ALLOCA_N(char, strlen(RSTRING(fname)->ptr) + 5); strcpy(buf, RSTRING(fname)->ptr); strcat(buf, ".rb"); - file = rb_find_file(buf); - if (file) { - fname = rb_str_new2(file); + if (rb_find_file(buf)) { + fname = rb_str_new2(buf); feature = buf; goto load_rb; } @@ -6490,8 +6491,9 @@ thread_switch(n) break; case RESTORE_NORMAL: default: - return 1; + break; } + return 1; } #define THREAD_SAVE_CONTEXT(th) \ diff --git a/ext/etc/etc.c b/ext/etc/etc.c index e5f69f9285..049b94ec8f 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -10,6 +10,11 @@ #include "ruby.h" +#include +#ifdef HAVE_UNISTD_H +#include +#endif + #ifdef HAVE_GETPWENT #include #endif diff --git a/ext/md5/depend b/ext/md5/depend index c99f78ee90..14427861f8 100644 --- a/ext/md5/depend +++ b/ext/md5/depend @@ -1,2 +1,2 @@ -md5c.o: md5c.c md5.h +md5c.o: md5c.c md5.h $(topdir)/config.h md5init.o: md5init.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h md5.h diff --git a/ext/socket/socket.c b/ext/socket/socket.c index bbd5057741..cadadd2b6c 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -15,6 +15,11 @@ #include "rubysig.h" #include #include + +#ifdef HAVE_UNISTD_H +#include +#endif + #ifndef NT #include #include @@ -538,7 +543,7 @@ ip_addrsetup(host, port) portp = 0; } else if (FIXNUM_P(port)) { - snprintf(pbuf, sizeof(pbuf), "%d", FIX2INT(port)); + snprintf(pbuf, sizeof(pbuf), "%ld", FIX2INT(port)); portp = pbuf; } else { @@ -726,7 +731,7 @@ open_inet(class, h, serv, type) host = NULL; } if (FIXNUM_P(serv)) { - snprintf(pbuf, sizeof(pbuf), "%d", FIX2UINT(serv)); + snprintf(pbuf, sizeof(pbuf), "%ld", FIX2UINT(serv)); portp = pbuf; } else { @@ -1748,7 +1753,7 @@ sock_s_getaddrinfo(argc, argv) pptr = NULL; } else if (FIXNUM_P(port)) { - snprintf(pbuf, sizeof(pbuf), "%d", FIX2INT(port)); + snprintf(pbuf, sizeof(pbuf), "%ld", FIX2INT(port)); pptr = pbuf; } else { @@ -1788,7 +1793,7 @@ sock_s_getnameinfo(argc, argv) int argc; VALUE *argv; { - VALUE sa, af, host, port, flags; + VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags; static char hbuf[1024], pbuf[1024]; char *hptr, *pptr; int fl; @@ -1824,6 +1829,10 @@ sock_s_getnameinfo(argc, argv) host = RARRAY(sa)->ptr[2]; } } + else { + rb_raise(rb_eArgError, "array size should be 3 or 4, %d given", + RARRAY(sa)->len); + } if (NIL_P(host)) { hptr = NULL; } @@ -1837,7 +1846,7 @@ sock_s_getnameinfo(argc, argv) pptr = NULL; } else if (!NIL_P(port)) { - snprintf(pbuf, sizeof(pbuf), "%d", NUM2INT(port)); + snprintf(pbuf, sizeof(pbuf), "%ld", NUM2INT(port)); pptr = pbuf; } else { @@ -1872,7 +1881,6 @@ sock_s_getnameinfo(argc, argv) fl = NUM2INT(flags); } - gotsap: error = getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), fl); if (error) { diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h index 99bec91a1a..1639fcf828 100644 --- a/ext/socket/sockport.h +++ b/ext/socket/sockport.h @@ -37,7 +37,7 @@ # define SET_SIN_LEN(si,len) (si)->sin_len = (len) #else # define SIN_LEN(si) sizeof(struct sockaddr_in) -# define SET_SIN_LEN(si,len) (len) +# define SET_SIN_LEN(si,len) #endif #endif diff --git a/file.c b/file.c index 19e44c4d13..421929d96f 100644 --- a/file.c +++ b/file.c @@ -25,6 +25,12 @@ #include #endif +#ifdef HAVE_SYS_FILE_H +# include +#else +int flock _((int, int)); +#endif + #ifdef HAVE_SYS_PARAM_H # include #else @@ -875,6 +881,7 @@ rb_file_s_chmod(argc, argv) VALUE rest; int mode, n; + rb_secure(2); rb_scan_args(argc, argv, "1*", &vmode, &rest); mode = NUM2INT(vmode); @@ -927,6 +934,7 @@ rb_file_s_chown(argc, argv) struct chown_args arg; int n; + rb_secure(2); rb_scan_args(argc, argv, "2*", &o, &g, &rest); if (NIL_P(o)) { arg.owner = -1; @@ -1377,6 +1385,7 @@ static VALUE rb_file_s_truncate(obj, path, len) VALUE obj, path, len; { + rb_secure(2); Check_SafeStr(path); #ifdef HAVE_TRUNCATE diff --git a/gc.c b/gc.c index 086715a569..edb290fbc4 100644 --- a/gc.c +++ b/gc.c @@ -52,7 +52,6 @@ static unsigned long malloc_memories = 0; static unsigned long alloc_objects = 0; static int malloc_called = 0; -static int second_mem_error = 0; static void mem_error(mesg) @@ -947,11 +946,7 @@ rb_gc() setjmp(save_regs_gc_mark); mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END); -#if defined(THINK_C) || defined(__human68k__) -#ifndef __human68k__ - mark_locations_array((VALUE*)((char*)save_regs_gc_mark+2), - sizeof(save_regs_gc_mark) / sizeof(VALUE *)); -#endif +#if defined(__human68k__) rb_gc_mark_locations((VALUE*)((char*)rb_gc_stack_start + 2), (VALUE*)((char*)STACK_END + 2)); #endif diff --git a/hash.c b/hash.c index 14afcbb7f3..dc8bdf5f45 100644 --- a/hash.c +++ b/hash.c @@ -688,8 +688,6 @@ static VALUE rb_hash_to_s(hash) VALUE hash; { - VALUE str; - if (rb_inspecting_p(hash)) return rb_str_new2("{...}"); return rb_protect_inspect(to_s_hash, hash, 0); } @@ -929,8 +927,6 @@ env_fetch(argc, argv) char *nam, *env; int len; - VALUE val; - rb_scan_args(argc, argv, "11", &key, &if_none); nam = rb_str2cstr(key, &len); if (strlen(nam) != len) { diff --git a/intern.h b/intern.h index 81b1a53a04..e0c365fdca 100644 --- a/intern.h +++ b/intern.h @@ -68,6 +68,7 @@ double rb_big2dbl _((VALUE)); VALUE rb_big_plus _((VALUE, VALUE)); VALUE rb_big_minus _((VALUE, VALUE)); VALUE rb_big_mul _((VALUE, VALUE)); +VALUE rb_big_divmod _((VALUE, VALUE)); VALUE rb_big_pow _((VALUE, VALUE)); VALUE rb_big_and _((VALUE, VALUE)); VALUE rb_big_or _((VALUE, VALUE)); @@ -105,6 +106,7 @@ VALUE rb_exc_new3 _((VALUE, VALUE)); void rb_loaderror __((const char*, ...)) NORETURN; void rb_compile_error __((const char*, ...)); void rb_compile_error_append __((const char*, ...)); +void rb_error_frozen _((char*)); /* eval.c */ void rb_exc_raise _((VALUE)) NORETURN; void rb_exc_fatal _((VALUE)) NORETURN; @@ -219,6 +221,7 @@ VALUE rb_obj_clone _((VALUE)); VALUE rb_obj_taint _((VALUE)); VALUE rb_obj_tainted _((VALUE)); VALUE rb_obj_untaint _((VALUE)); +VALUE rb_obj_freeze _((VALUE)); VALUE rb_obj_id _((VALUE)); VALUE rb_convert_type _((VALUE,int,const char*,const char*)); VALUE rb_Integer _((VALUE)); @@ -240,6 +243,7 @@ void rb_parser_append_print _((void)); void rb_parser_while_loop _((int, int)); int rb_is_const_id _((ID)); int rb_is_instance_id _((ID)); +int rb_is_class_id _((ID)); VALUE rb_backref_get _((void)); void rb_backref_set _((VALUE)); VALUE rb_lastline_get _((void)); @@ -352,8 +356,12 @@ int rb_const_defined _((VALUE, ID)); VALUE rb_const_get _((VALUE, ID)); VALUE rb_const_get_at _((VALUE, ID)); void rb_const_set _((VALUE, ID, VALUE)); +void rb_const_assign _((VALUE, ID, VALUE)); VALUE rb_mod_constants _((VALUE)); void rb_autoload_load _((ID)); +void rb_cvar_declare _((VALUE, ID, VALUE)); +VALUE rb_cvar_get _((VALUE, ID)); +void rb_cvar_set _((VALUE, ID, VALUE)); /* version.c */ void ruby_show_version _((void)); void ruby_show_copyright _((void)); diff --git a/io.c b/io.c index 380e7d4115..9a5ef85845 100644 --- a/io.c +++ b/io.c @@ -63,7 +63,7 @@ char *strdup(); extern void Init_File _((void)); #ifdef __BEOS__ -# ifdef _X86_ +# ifdef NOFILE # define NOFILE (OPEN_MAX) # endif #include @@ -170,6 +170,25 @@ rb_read_check(fp) } } +static int +rb_dup(orig) + int orig; +{ + int fd; + + fd = dup(orig); + if (fd < 0) { + if (errno == EMFILE || errno == ENFILE) { + rb_gc(); + fd = dup(orig); + } + if (fd < 0) { + rb_sys_fail(0); + } + } + return fd; +} + /* writing functions */ static VALUE io_write(io, str) @@ -1893,10 +1912,10 @@ rb_io_clone(io) else mode = "r+"; break; } - fd = dup(fileno(orig->f)); + fd = rb_dup(fileno(orig->f)); fptr->f = rb_fdopen(fd, mode); if (fptr->f2) { - fd = dup(fileno(orig->f2)); + fd = rb_dup(fileno(orig->f2)); fptr->f = rb_fdopen(fd, "w"); } if (fptr->mode & FMODE_BINMODE) { @@ -2126,25 +2145,6 @@ rb_io_defset(val, id) rb_defout = val; } -static int -rb_dup(orig) - int orig; -{ - int fd; - - fd = dup(orig); - if (fd < 0) { - if (errno == EMFILE || errno == ENFILE) { - rb_gc(); - fd = dup(orig); - } - if (fd < 0) { - rb_sys_fail(0); - } - } - return fd; -} - static void set_stdin(val, id, var) VALUE val; @@ -2152,8 +2152,6 @@ set_stdin(val, id, var) VALUE *var; { OpenFile *fptr; - int fd; - char *mode; if (val == *var) return; if (TYPE(val) != T_FILE) { @@ -2180,8 +2178,6 @@ set_outfile(val, var, orig, stdf) { OpenFile *fptr; FILE *f; - int fd; - char *mode; if (val == *var) return; @@ -2247,7 +2243,6 @@ rb_io_s_new(argc, argv, klass) VALUE *argv; VALUE klass; { - OpenFile *fp; NEWOBJ(io, struct RFile); OBJSETUP(io, klass, T_FILE); diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb new file mode 100644 index 0000000000..cbd4012773 --- /dev/null +++ b/lib/irb/completion.rb @@ -0,0 +1,47 @@ + +require "readline" + +module IRB + module InputCompletion + ReservedWords = [ + "BEGIN", "END", + "alias", "and", + "begin", "break", + "case", "class", + "def", "defined", "do", + "else", "elsif", "end", "ensure", + "false", "for", + "if", "in", + "module", + "next", "nil", "not", + "or", + "redo", "rescue", "retry", "return", + "self", "super", + "then", "true", + "undef", "unless", "until", + "when", "while", + "yield" + ] + + CompletionProc = proc { |input| + case input + when /^([^.]+)\.([^.]*)$/ + receiver = $1 + message = $2 + if eval("(local_variables|#{receiver}.type.constants).include?('#{receiver}')", + IRB.conf[:MAIN_CONTEXT].bind) + candidates = eval("#{receiver}.methods", IRB.conf[:MAIN_CONTEXT].bind) + else + candidates = [] + end + candidates.grep(/^#{Regexp.quote(message)}/).collect{|e| receiver + "." + e} + else + candidates = eval("methods | private_methods | local_variables | type.constants", + IRB.conf[:MAIN_CONTEXT].bind) + (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/) + end + } + end +end + +Readline.completion_proc = IRB::InputCompletion::CompletionProc diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb new file mode 100644 index 0000000000..a2d7de3778 --- /dev/null +++ b/lib/irb/frame.rb @@ -0,0 +1,67 @@ +# +# frame.rb - +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +require "e2mmap" + +module IRB + class Frame + extend Exception2MessageMapper + def_exception :FrameOverflow, "frame overflow" + def_exception :FrameUnderflow, "frame underflow" + + INIT_STACK_TIMES = 3 + CALL_STACK_OFFSET = 3 + + def initialize + @frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES + end + + def trace_func(event, file, line, id, binding) + case event + when 'call', 'class' + @frames.push binding + when 'return', 'end' + @frames.pop + end + end + + def top(n = 0) + bind = @frames[-(n + CALL_STACK_OFFSET)] + Fail FrameUnderflow unless bind + bind + end + + def bottom(n = 0) + bind = @frames[n] + Fail FrameOverflow unless bind + bind + end + + # singleton functions + def Frame.bottom(n = 0) + @backtrace.bottom(n) + end + + def Frame.top(n = 0) + @backtrace.top(n) + end + + def Frame.sender + eval "self", @backtrace.top + end + + @backtrace = Frame.new + set_trace_func proc{|event, file, line, id, binding| + @backtrace.trace_func(event, file, line, id, binding) + } + end +end diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb new file mode 100644 index 0000000000..19df0eb073 --- /dev/null +++ b/lib/irb/input-method.rb @@ -0,0 +1,118 @@ +# +# input-method.rb - input methods using irb +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# +module IRB + # + # InputMethod + # StdioInputMethod + # FileInputMethod + # (ReadlineInputMethod) + # + STDIN_FILE_NAME = "(line)" + class InputMethod + @RCS_ID='-$Id$-' + + def initialize(file = STDIN_FILE_NAME) + @file_name = file + end + attr :file_name + + attr :prompt, true + + def gets + IRB.fail NotImplementError, "gets" + end + public :gets + + def readable_atfer_eof? + false + end + end + + class StdioInputMethod < InputMethod + def initialize + super + @line_no = 0 + @line = [] + end + + def gets + print @prompt + @line[@line_no += 1] = $stdin.gets + end + + def eof? + $stdin.eof? + end + + def readable_atfer_eof? + true + end + + def line(line_no) + @line[line_no] + end + end + + class FileInputMethod < InputMethod + def initialize(file) + super + @io = open(file) + end + attr :file_name + + def eof? + @io.eof? + end + + def gets + l = @io.gets + print @prompt, l + l + end + end + + begin + require "readline" + class ReadlineInputMethod < InputMethod + include Readline + def initialize + super + + @line_no = 0 + @line = [] + @eof = false + end + + def gets + if l = readline(@prompt, true) + @line[@line_no += 1] = l + "\n" + else + @eof = true + l + end + end + + def eof? + @eof + end + + def readable_atfer_eof? + true + end + + def line(line_no) + @line[line_no] + end + end + rescue LoadError + end +end diff --git a/lib/irb/loader.rb b/lib/irb/loader.rb new file mode 100644 index 0000000000..83b10a55a0 --- /dev/null +++ b/lib/irb/loader.rb @@ -0,0 +1,118 @@ +# +# irb-loader.rb - +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +module IRB + class LoadAbort < GlobalExit;end + + module Loader + @RCS_ID='-$Id$-' + + alias ruby_load load + alias ruby_require require + + def irb_load(file_name) + return ruby_load(file_name) unless IRB.conf[:USE_LOADER] + + load_sub(file_name) + return true + end + + def irb_require(file_name) + return ruby_require(file_name) unless IRB.conf[:USE_LOADER] + + rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?") + return false if $".find{|f| f =~ rex} + + case file_name + when /\.rb$/ + begin + load_sub(file_name) + $".push file_name + return true + rescue LoadError + end + when /\.(so|o|sl)$/ + return ruby_require(file_name) + end + + begin + load_sub(f = file_name + ".rb") + $".push f + return true + rescue LoadError + return ruby_require(file_name) + end + end + + def load_sub(fn) + if fn =~ /^#{Regexp.quote(File::Separator)}/ + return false unless File.exist?(fn) + return irb_context.load_file(fn) + end + + for path in $: + if File.exist?(f = File.join(path, fn)) + return irb_context.load_file(f) + end + end + raise LoadError, "No such file to load -- #{file_name}" + end + + alias load irb_load + alias require irb_require + end + +# class Context +# def load_from(file_name) +# io = FileInputMethod.new(file_name) +# @irb.signal_status(:IN_LOAD) do +# switch_io(io, file_name) do +# eval_input +# end +# end +# end +# end + + class Context + def load_file(path) + back_io = @io + back_path = @irb_path + back_name = @irb_name + back_scanner = @irb.scanner + begin + @io = FileInputMethod.new(path) + @irb_name = File.basename(path) + @irb_path = path + @irb.signal_status(:IN_LOAD) do + if back_io.kind_of?(FileInputMethod) + @irb.eval_input + else + begin + @irb.eval_input + rescue LoadAbort + print "load abort!!\n" + end + end + end + ensure + @io = back_io + @irb_name = back_name + @irb_path = back_path + @irb.scanner = back_scanner + end + end + end + + module ExtendCommand + include Loader + end +end diff --git a/lib/irb/main.rb b/lib/irb/main.rb new file mode 100644 index 0000000000..4c7dac240b --- /dev/null +++ b/lib/irb/main.rb @@ -0,0 +1,867 @@ +# +# main.rb - irb main module +# $Release Version: 0.6 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# +require "e2mmap" +require "irb/ruby-lex" +require "irb/input-method" +require "irb/workspace-binding" + +STDOUT.sync = true + +module IRB + @RCS_ID='-$Id$-' + + # exceptions + extend Exception2MessageMapper + def_exception :UnrecognizedSwitch, "Unrecognized switch: %s" + def_exception :NotImplementError, "Need to define `%s'" + def_exception :CantRetuenNormalMode, "Can't return normal mode." + def_exception :IllegalParameter, "Illegal parameter(%s)." + def_exception :IrbAlreadyDead, "Irb is already dead." + def_exception :IrbSwitchToCurrentThread, "Change to current thread." + def_exception :NoSuchJob, "No such job(%s)." + def_exception :CanNotGoMultiIrbMode, "Can't go multi irb mode." + def_exception :CanNotChangeBinding, "Can't change binding to (%s)." + def_exception :UndefinedPromptMode, "Undefined prompt mode(%s)." + + class Abort < Exception;end + + # initialize IRB and start TOP_LEVEL irb + def IRB.start(ap_path = nil) + $0 = File::basename(ap_path, ".rb") if ap_path + + IRB.initialize(ap_path) + IRB.parse_opts + IRB.load_modules + + bind = workspace_binding + main = eval("self", bind) + + if @CONF[:SCRIPT] + irb = Irb.new(main, bind, @CONF[:SCRIPT]) + else + irb = Irb.new(main, bind) + end + + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] + @CONF[:MAIN_CONTEXT] = irb.context + + trap("SIGINT") do + irb.signal_handle + end + + catch(:IRB_EXIT) do + irb.eval_input + end + print "\n" + end + + # initialize config + def IRB.initialize(ap_path) + IRB.init_config(ap_path) + IRB.run_config + end + + # + # @CONF functions + # + @CONF = {} + # @CONF default setting + def IRB.init_config(ap_path) + # class instance variables + @TRACER_INITIALIZED = false + @MATHN_INITIALIZED = false + + # default configurations + unless ap_path and @CONF[:AP_NAME] + ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb") + end + @CONF[:AP_NAME] = File::basename(ap_path, ".rb") + + @CONF[:IRB_NAME] = "irb" + @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__) + + @CONF[:RC] = true + @CONF[:LOAD_MODULES] = [] + @CONF[:IRB_RC] = nil + + @CONF[:MATH_MODE] = false + @CONF[:USE_READLINE] = false unless defined?(ReadlineInputMethod) + @CONF[:INSPECT_MODE] = nil + @CONF[:USE_TRACER] = false + @CONF[:USE_LOADER] = false + @CONF[:IGNORE_SIGINT] = true + @CONF[:IGNORE_EOF] = false + + @CONF[:BACK_TRACE_LIMIT] = 16 + + @CONF[:PROMPT] = { + :NULL => { + :PROMPT_I => nil, + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => "%s\n" + }, + :DEFAULT => { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => "%N(%m):%03n:%i%l ", + :PROMPT_C => "%N(%m):%03n:%i* ", + :RETURN => "%s\n" + }, + :SIMPLE => { + :PROMPT_I => ">> ", + :PROMPT_S => nil, + :PROMPT_C => "?> ", + :RETURN => "=> %s\n" + }, + :INF_RUBY => { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => "%s\n", + :AUTO_INDENT => true + }, + :XMP => { + :PROMPT_I => nil, + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => " ==>%s\n" + } + } + + @CONF[:PROMPT_MODE] = :DEFAULT + @CONF[:AUTO_INDENT] = false + + @CONF[:CONTEXT_MODE] = 3 + @CONF[:SINGLE_IRB] = false + + @CONF[:DEBUG_LEVEL] = 1 + @CONF[:VERBOSE] = true + end + + # IRB version method + def IRB.version + if v = @CONF[:VERSION] then return v end + + require "irb/version" + rv = @RELEASE_VERSION.sub(/\.0/, "") + @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE) + end + + def IRB.conf + @CONF + end + + # option analyzing + def IRB.parse_opts + while opt = ARGV.shift + case opt + when "-f" + opt = ARGV.shift + @CONF[:RC] = false + when "-m" + @CONF[:MATH_MODE] = true + when "-d" + $DEBUG = true + when "-r" + opt = ARGV.shift + @CONF[:LOAD_MODULES].push opt if opt + when "--inspect" + @CONF[:INSPECT_MODE] = true + when "--noinspect" + @CONF[:INSPECT_MODE] = false + when "--readline" + @CONF[:USE_READLINE] = true + when "--noreadline" + @CONF[:USE_READLINE] = false + when "--prompt-mode", "--prompt" + prompt_mode = ARGV.shift.upcase.tr("-", "_").intern + IRB.fail(UndefinedPromptMode, + prompt_mode.id2name) unless @CONF[:PROMPT][prompt_mode] + @CONF[:PROMPT_MODE] = prompt_mode + when "--noprompt" + @CONF[:PROMPT_MODE] = :NULL + when "--inf-ruby-mode" + @CONF[:PROMPT_MODE] = :INF_RUBY + when "--sample-book-mode", "--simple-prompt" + @CONF[:PROMPT_MODE] = :SIMPLE + when "--tracer" + @CONF[:USE_TRACER] = true + when "--back-trace-limit" + @CONF[:BACK_TRACE_LIMIT] = ARGV.shift.to_i + when "--context-mode" + @CONF[:CONTEXT_MODE] = ARGV.shift.to_i + when "--single-irb" + @CONF[:SINGLE_IRB] = true + when "--irb_debug" + @CONF[:DEBUG_LEVEL] = ARGV.shift.to_i + when "-v", "--version" + print IRB.version, "\n" + exit(0) + when /^-/ + IRB.fail UnrecognizedSwitch, opt + else + @CONF[:USE_READLINE] = false + @CONF[:SCRIPT] = opt + $0 = opt + break + end + end + end + + # running config + def IRB.run_config + if @CONF[:RC] + rcs = [] + rcs.push File.expand_path("~/.irbrc") if ENV.key?("HOME") + rcs.push ".irbrc" + rcs.push "irb.rc" + rcs.push "_irbrc" + rcs.push "$irbrc" + catch(:EXIT) do + for rc in rcs + begin + load rc + throw :EXIT + rescue LoadError, Errno::ENOENT + rescue + print "load error: #{rc}\n" + print $!.type, ": ", $!, "\n" + for err in $@[0, $@.size - 2] + print "\t", err, "\n" + end + throw :EXIT + end + end + end + end + end + + # loading modules + def IRB.load_modules + for m in @CONF[:LOAD_MODULES] + begin + require m + rescue + print $@[0], ":", $!.type, ": ", $!, "\n" + end + end + end + + # initialize tracing function + def IRB.initialize_tracer + unless @TRACER_INITIALIZED + require("tracer") + Tracer.verbose = false + Tracer.add_filter { + |event, file, line, id, binding| + File::dirname(file) != @CONF[:IRB_LIB_PATH] + } + @TRACER_INITIALIZED = true + end + end + + # initialize mathn function + def IRB.initialize_mathn + unless @MATHN_INITIALIZED + require "mathn" + @MATHN_INITIALIZED = true + end + end + + # initialize loader function + def IRB.initialize_loader + unless @LOADER_INITIALIZED + require "irb/loader" + @LOADER_INITIALIZED = true + end + end + + def IRB.irb_exit(irb, ret) + throw :IRB_EXIT, ret + end + + def IRB.irb_abort(irb, exception = Abort) + if defined? Thread + irb.context.thread.raise exception, "abort then interrupt!!" + else + raise exception, "abort then interrupt!!" + end + end + + # + # irb interpriter main routine + # + class Irb + def initialize(main, bind, input_method = nil) + @context = Context.new(self, main, bind, input_method) + main.extend ExtendCommand + @signal_status = :IN_IRB + + @scanner = RubyLex.new + @scanner.exception_on_syntax_error = false + end + attr :context + attr :scanner, true + + def eval_input +# @scanner = RubyLex.new + @scanner.set_input(@context.io) do + signal_status(:IN_INPUT) do + unless l = @context.io.gets + if @context.ignore_eof? and @context.io.readable_atfer_eof? + l = "\n" + if @context.verbose? + printf "Use \"exit\" to leave %s\n", @context.ap_name + end + end + end + l + end + end + + @scanner.set_prompt do + |ltype, indent, continue, line_no| + if ltype + f = @context.prompt_s + elsif continue + f = @context.prompt_c + else @context.prompt_i + f = @context.prompt_i + end + f = "" unless f + @context.io.prompt = p = prompt(f, ltype, indent, line_no) + if @context.auto_indent_mode + unless ltype + ind = prompt(@context.prompt_i, ltype, indent, line_no).size + + indent * 2 - p.size + ind += 2 if continue + @context.io.prompt = p + " " * ind if ind > 0 + end + end + end + + @scanner.each_top_level_statement do + |line, line_no| + signal_status(:IN_EVAL) do + begin + trace_in do + @context._ = eval(line, @context.bind, @context.irb_path, line_no) +# @context._ = irb_eval(line, @context.bind, @context.irb_path, line_no) + end + + if @context.inspect? + printf @context.return_format, @context._.inspect + else + printf @context.return_format, @context._ + end + rescue StandardError, ScriptError, Abort + $! = RuntimeError.new("unknown exception raised") unless $! + print $!.type, ": ", $!, "\n" + if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.type.to_s !~ /^IRB/ + irb_bug = true + else + irb_bug = false + end + + messages = [] + lasts = [] + levels = 0 + for m in $@ + if m !~ /irb2?(\/.*|-.*|\.rb)?:/ or irb_bug + if messages.size < @context.back_trace_limit + messages.push m + else + lasts.push m + if lasts.size > @context.back_trace_limit + lasts.shift + levels += 1 + end + end + end + end + print messages.join("\n"), "\n" + unless lasts.empty? + printf "... %d levels...\n", levels if levels > 0 + print lasts.join("\n") + end + print "Maybe IRB bug!!\n" if irb_bug + end + end + end + end + +# def irb_eval(line, bind, path, line_no) +# id, str = catch(:IRB_TOPLEVEL_EVAL){ +# return eval(line, bind, path, line_no) +# } +# case id +# when :EVAL_TOPLEVEL +# eval(str, bind, "(irb_internal)", 1) +# when :EVAL_CONTEXT +# @context.instance_eval(str) +# else +# IRB.fail IllegalParameter +# end +# end + + def signal_handle + unless @context.ignore_sigint? + print "\nabort!!\n" if @context.verbose? + exit + end + + case @signal_status + when :IN_INPUT + print "^C\n" + @scanner.initialize_input + print @context.io.prompt + when :IN_EVAL + IRB.irb_abort(self) + when :IN_LOAD + IRB.irb_abort(self, LoadAbort) + when :IN_IRB + # ignore + else + # ignore + end + end + + def signal_status(status) + return yield if @signal_status == :IN_LOAD + + signal_status_back = @signal_status + @signal_status = status + begin + yield + ensure + @signal_status = signal_status_back + end + end + + def trace_in + Tracer.on if @context.use_tracer? + begin + yield + ensure + Tracer.off if @context.use_tracer? + end + end + + def prompt(prompt, ltype, indent, line_no) + p = prompt.dup + p.gsub!(/%([0-9]+)?([a-zA-Z])/) do + case $2 + when "N" + @context.irb_name + when "m" + @context.main.to_s + when "M" + @context.main.inspect + when "l" + ltype + when "i" + if $1 + format("%" + $1 + "d", indent) + else + indent.to_s + end + when "n" + if $1 + format("%" + $1 + "d", line_no) + else + line_no.to_s + end + when "%" + "%" + end + end + p + end + + def inspect + ary = [] + for iv in instance_variables + case iv + when "@signal_status" + ary.push format("%s=:%s", iv, @signal_status.id2name) + when "@context" + ary.push format("%s=%s", iv, eval(iv).__to_s__) + else + ary.push format("%s=%s", iv, eval(iv)) + end + end + format("#<%s: %s>", type, ary.join(", ")) + end + end + + # + # irb context + # + class Context + # + # Arguments: + # input_method: nil -- stdin or readline + # String -- File + # other -- using this as InputMethod + # + def initialize(irb, main, bind, input_method = nil) + @irb = irb + @main = main + @bind = bind + @thread = Thread.current if defined? Thread + @irb_level = 0 + + # copy of default configuration + @ap_name = IRB.conf[:AP_NAME] + @rc = IRB.conf[:RC] + @load_modules = IRB.conf[:LOAD_MODULES] + + self.math_mode = IRB.conf[:MATH_MODE] + @use_readline = IRB.conf[:USE_READLINE] + @inspect_mode = IRB.conf[:INSPECT_MODE] + @use_tracer = IRB.conf[:USE_TRACER] +# @use_loader = IRB.conf[:USE_LOADER] + + self.prompt_mode = IRB.conf[:PROMPT_MODE] + + @ignore_sigint = IRB.conf[:IGNORE_SIGINT] + @ignore_eof = IRB.conf[:IGNORE_EOF] + + @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] + + debug_level = IRB.conf[:DEBUG_LEVEL] + @verbose = IRB.conf[:VERBOSE] + + @tracer_initialized = false + + if IRB.conf[:SINGLE_IRB] or !defined?(JobManager) + @irb_name = IRB.conf[:IRB_NAME] + else + @irb_name = "irb#"+IRB.JobManager.n_jobs.to_s + end + @irb_path = "(" + @irb_name + ")" + + case input_method + when nil + if (use_readline.nil? && IRB.conf[:PROMPT_MODE] != :INF_RUBY || + use_readline?) + @io = ReadlineInputMethod.new + else + @io = StdioInputMethod.new + end + when String + @io = FileInputMethod.new(input_method) + @irb_name = File.basename(input_method) + @irb_path = input_method + else + @io = input_method + end + end + + attr :bind, true + attr :main, true + attr :thread + attr :io, true + + attr :_ + + attr :irb + attr :ap_name + attr :rc + attr :load_modules + attr :irb_name + attr :irb_path + + attr :math_mode, true + attr :use_readline, true + attr :inspect_mode + attr :use_tracer +# attr :use_loader + + attr :debug_level + attr :verbose, true + + attr :prompt_mode + attr :prompt_i, true + attr :prompt_s, true + attr :prompt_c, true + attr :auto_indent_mode, true + attr :return_format, true + + attr :ignore_sigint, true + attr :ignore_eof, true + + attr :back_trace_limit + +# alias use_loader? use_loader + alias use_tracer? use_tracer + alias use_readline? use_readline + alias rc? rc + alias math? math_mode + alias verbose? verbose + alias ignore_sigint? ignore_sigint + alias ignore_eof? ignore_eof + + def _=(value) + @_ = value + eval "_ = IRB.conf[:MAIN_CONTEXT]._", @bind + end + + def irb_name + if @irb_level == 0 + @irb_name + elsif @irb_name =~ /#[0-9]*$/ + @irb_name + "." + @irb_level.to_s + else + @irb_name + "#0." + @irb_level.to_s + end + end + + def prompt_mode=(mode) + @prompt_mode = mode + pconf = IRB.conf[:PROMPT][mode] + @prompt_i = pconf[:PROMPT_I] + @prompt_s = pconf[:PROMPT_S] + @prompt_c = pconf[:PROMPT_C] + @return_format = pconf[:RETURN] + if ai = pconf.include?(:AUTO_INDENT) + @auto_indent_mode = ai + else + @auto_indent_mode = IRB.conf[:AUTO_INDENT] + end + end + + def inspect? + @inspect_mode.nil? && !@math_mode or @inspect_mode + end + + def file_input? + @io.type == FileInputMethod + end + + def use_tracer=(opt) + if opt + IRB.initialize_tracer + unless @tracer_initialized + Tracer.set_get_line_procs(@irb_path) { + |line_no| + @io.line(line_no) + } + @tracer_initialized = true + end + elsif !opt && @use_tracer + Tracer.off + end + @use_tracer=opt + end + + def use_loader + IRB.conf[:USE_LOADER] + end + + def use_loader=(opt) + IRB.conf[:USE_LOADER] = opt + if opt + IRB.initialize_loader + end + print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? + opt + end + + def inspect_mode=(opt) + if opt + @inspect_mode = opt + else + @inspect_mode = !@inspect_mode + end + print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? + @inspect_mode + end + + def math_mode=(opt) + if @math_mode == true && opt == false + IRB.fail CantRetuenNormalMode + return + end + + @math_mode = opt + if math_mode + IRB.initialize_mathn + @main.instance_eval("include Math") + print "start math mode\n" if verbose? + end + end + + def use_readline=(opt) + @use_readline = opt + print "use readline module\n" if @use_readline + end + + def debug_level=(value) + @debug_level = value + RubyLex.debug_level = value + SLex.debug_level = value + end + + def debug? + @debug_level > 0 + end + + def change_binding(*main) + back = [@bind, @main] + @bind = IRB.workspace_binding(*main) + unless main.empty? + @main = eval("self", @bind) + begin + @main.extend ExtendCommand + rescue + print "can't change binding to: ", @main.inspect, "\n" + @bind, @main = back + return nil + end + end + @irb_level += 1 + begin + catch(:SU_EXIT) do + @irb.eval_input + end + ensure + @irb_level -= 1 + @bind, @main = back + end + end + + alias __exit__ exit + def exit(ret = 0) + if @irb_level == 0 + IRB.irb_exit(@irb, ret) + else + throw :SU_EXIT, ret + end + end + + NOPRINTING_IVARS = ["@_"] + NO_INSPECTING_IVARS = ["@irb", "@io"] + IDNAME_IVARS = ["@prompt_mode"] + + alias __inspect__ inspect + def inspect + array = [] + for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} + name = ivar.sub(/^@(.*)$/){$1} + val = instance_eval(ivar) + case ivar + when *NOPRINTING_IVARS + next + when *NO_INSPECTING_IVARS + array.push format("conf.%s=%s", name, val.to_s) + when *IDNAME_IVARS + array.push format("conf.%s=:%s", name, val.id2name) + else + array.push format("conf.%s=%s", name, val.inspect) + end + end + array.join("\n") + end + alias __to_s__ to_s + alias to_s inspect + + end + + # + # IRB extended command + # + module Loader; end + module ExtendCommand + include Loader + + alias irb_exit_org exit + def irb_exit(ret = 0) + irb_context.exit(ret) + end + alias exit irb_exit + alias quit irb_exit + + alias irb_fork fork + def fork(&block) + unless irb_fork + eval "alias exit irb_exit_org" + instance_eval "alias exit irb_exit_org" + if iterator? + yield + exit + end + end + end + + def irb_change_binding(*main) + irb_context.change_binding(*main) + end + alias cb irb_change_binding + + def irb_source(file) + irb_context.source(file) + end + alias source irb_source + + def irb(*obj) + require "irb/multi-irb" + IRB.irb(nil, *obj) + end + + def irb_context + IRB.conf[:MAIN_CONTEXT] + end + alias conf irb_context + + def irb_jobs + require "irb/multi-irb" + IRB.JobManager + end + alias jobs irb_jobs + + def irb_fg(key) + require "irb/multi-irb" + IRB.JobManager.switch(key) + end + alias fg irb_fg + + def irb_kill(*keys) + require "irb/multi-irb" + IRB.JobManager.kill(*keys) + end + alias kill irb_kill + end + + # Singleton method + def @CONF.inspect + IRB.version unless self[:VERSION] + + array = [] + for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} + case k + when :MAIN_CONTEXT + next + when :PROMPT + s = v.collect{ + |kk, vv| + ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} + format(":%s=>{%s}", kk.id2name, ss.join(", ")) + } + array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) + else + array.push format("CONF[:%s]=%s", k.id2name, v.inspect) + end + end + array.join("\n") + end +end diff --git a/lib/irb/multi-irb.rb b/lib/irb/multi-irb.rb new file mode 100644 index 0000000000..39dbcbae3c --- /dev/null +++ b/lib/irb/multi-irb.rb @@ -0,0 +1,212 @@ +# +# multi-irb.rb - multiple irb module +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# +IRB.fail CanNotGoMultiIrbMode unless defined?(Thread) +require "thread" + +module IRB + # job management class + class JobManager + @RCS_ID='-$Id$-' + + def initialize + # @jobs = [[thread, irb],...] + @jobs = [] + @current_job = nil + end + + attr :current_job, true + + def n_jobs + @jobs.size + end + + def thread(key) + th, irb = search(key) + irb + end + + def irb(key) + th, irb = search(key) + irb + end + + def main_thread + @jobs[0][0] + end + + def main_irb + @jobs[0][1] + end + + def insert(irb) + @jobs.push [Thread.current, irb] + end + + def switch(key) + th, irb = search(key) + IRB.fail IrbAlreadyDead unless th.alive? + IRB.fail IrbSwitchToCurrentThread if th == Thread.current + @current_job = irb + th.run + Thread.stop + @current_job = irb(Thread.current) + end + + def kill(*keys) + for key in keys + th, irb = search(key) + IRB.fail IrbAlreadyDead unless th.alive? + th.exit + end + end + + def search(key) + case key + when Integer + @jobs[key] + when Irb + @jobs.find{|k, v| v.equal?(irb)} + when Thread + @jobs.assoc(key) + else + assoc = @jobs.find{|k, v| v.context.main.equal?(key)} + IRB.fail NoSuchJob, key if assoc.nil? + assoc + end + end + + def delete(key) + case key + when Integer + IRB.fail NoSuchJob, key unless @jobs[key] + @jobs[key] = nil + else + catch (:EXISTS) do + @jobs.each_index do + |i| + if @jobs[i] and (@jobs[i][0] == key || + @jobs[i][1] == key || + @jobs[i][1].context.main.equal?(key)) + @jobs[i] = nil + throw :EXISTS + end + end + IRB.fail NoSuchJob, key + end + end + until assoc = @jobs.pop; end unless @jobs.empty? + @jobs.push assoc + end + + def inspect + ary = [] + @jobs.each_index do + |i| + th, irb = @jobs[i] + next if th.nil? + + if th.alive? + if th.stop? + t_status = "stop" + else + t_status = "running" + end + else + t_status = "exited" + end + ary.push format("#%d->%s on %s (%s: %s)", + i, + irb.context.irb_name, + irb.context.main, + th, + t_status) + end + ary.join("\n") + end + end + + @JobManager = JobManager.new + + def IRB.JobManager + @JobManager + end + + # invoke multiple irb + def IRB.irb(file = nil, *main) + workspace = IRB.workspace_binding(*main) + if main.empty? + main = eval("self", workspace) + else + main = main[0] + end + parent_thread = Thread.current + Thread.start do + begin + irb = Irb.new(main, workspace, file) + rescue + print "Subirb can't start with context(self): ", main.inspect, "\n" + print "return to main irb\n" + Thread.pass + Thread.main.wakeup + Thread.exit + end + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] + @JobManager.insert(irb) + begin + system_exit = false + catch(:IRB_EXIT) do + irb.eval_input + end + rescue SystemExit + system_exit = true + raise + #fail + ensure + unless system_exit + @JobManager.delete(irb) + if parent_thread.alive? + @JobManager.current_job = @JobManager.irb(parent_thread) + parent_thread.run + else + @JobManager.current_job = @JobManager.main_irb + @JobManager.main_thread.run + end + end + end + end + Thread.stop + @JobManager.current_job = @JobManager.irb(Thread.current) + end + + class Context + def _=(value) + @_ = value + eval "_ = IRB.JobManager.irb(Thread.current).context._", @bind + end + end + + module ExtendCommand + def irb_context + IRB.JobManager.irb(Thread.current).context + end + alias conf irb_context + end + + @CONF[:SINGLE_IRB_MODE] = false + @JobManager.insert(@CONF[:MAIN_CONTEXT].irb) + @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb + + trap("SIGINT") do + @JobManager.current_job.signal_handle + end + +end diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb new file mode 100644 index 0000000000..e66ba8879e --- /dev/null +++ b/lib/irb/ruby-lex.rb @@ -0,0 +1,955 @@ +# +# ruby-lex.rb - ruby lexcal analizer +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +require "e2mmap" +require "irb/slex" +require "irb/ruby-token" + +class RubyLex + @RCS_ID='-$Id$-' + + extend Exception2MessageMapper + def_exception(:AlreadyDefinedToken, "Already defined token(%s)") + def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkReading2TokenDuplicateError, + "key duplicate(token_n='%s', key='%s')") + def_exception(:SyntaxError, "%s") + + include RubyToken + + class << self + attr :debug_level, TRUE + def debug? + @debug_level > 0 + end + end + @debug_level = 0 + + def initialize + lex_init + set_input(STDIN) + + @seek = 0 + @exp_line_no = @line_no = 1 + @base_char_no = 0 + @char_no = 0 + @rests = [] + @readed = [] + @here_readed = [] + + @indent = 0 + + @skip_space = false + @readed_auto_clean_up = false + @exception_on_syntax_error = true + end + + attr :skip_space, true + attr :readed_auto_clean_up, true + attr :exception_on_syntax_error, true + + attr :seek + attr :char_no + attr :line_no + attr :indent + + # io functions + def set_input(io, p = nil) + @io = io + if p.kind_of?(Proc) + @input = p + elsif iterator? + @input = proc + else + @input = proc{@io.gets} + end + end + + def get_readed + if idx = @readed.reverse.index("\n") + @base_char_no = idx + else + @base_char_no += @readed.size + end + + readed = @readed.join("") + @readed = [] + readed + end + + def getc + while @rests.empty? + return nil unless buf_input + end + c = @rests.shift + if @here_header + @here_readed.push c + else + @readed.push c + end + @seek += 1 + if c == "\n" + @line_no += 1 + @char_no = 0 + else + @char_no += 1 + end + c + end + + def gets + l = "" + while c = getc + l.concat c + break if c == "\n" + end + l + end + + def eof? + @io.eof? + end + + def getc_of_rests + if @rests.empty? + nil + else + getc + end + end + + def ungetc(c = nil) + if @here_readed.empty? + c2 = @readed.pop + else + c2 = @here_readed.pop + end + c = c2 unless c + @rests.unshift c #c = + @seek -= 1 + if c == "\n" + @line_no -= 1 + if idx = @readed.reverse.index("\n") + @char_no = @readed.size - idx + else + @char_no = @base_char_no + @readed.size + end + else + @char_no -= 1 + end + end + + def peek_equal?(str) + chrs = str.split(//) + until @rests.size >= chrs.size + return false unless buf_input + end + @rests[0, chrs.size] == chrs + end + + def peek_match?(regexp) + while @rests.empty? + return false unless buf_input + end + regexp =~ @rests.join("") + end + + def peek(i = 0) + while @rests.size <= i + return nil unless buf_input + end + @rests[i] + end + + def buf_input + prompt + line = @input.call + return nil unless line + @rests.concat line.split(//) + true + end + private :buf_input + + def set_prompt(p = proc) + if p.kind_of?(Proc) + @prompt = p + else + @prompt = proc{print p} + end + end + + def prompt + if @prompt + @prompt.call(@ltype, @indent, @continue, @line_no) + end + end + + def initialize_input + @ltype = nil + @quoted = nil + @indent = 0 + @lex_state = EXPR_BEG + @space_seen = false + @here_header = false + + prompt + @continue = FALSE + + @line = "" + @exp_line_no = @line_no + end + + def each_top_level_statement + initialize_input + loop do + @continue = FALSE + prompt + unless l = lex + break if @line == '' + else + # p l + @line.concat l + if @ltype or @continue or @indent > 0 + next + end + end + if @line != "\n" + yield @line, @exp_line_no + end + break unless l + @line = '' + @exp_line_no = @line_no + + @indent = 0 + prompt + end + end + + def lex + until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && + !@continue or + tk.nil?) + # p tk + # p self + end + line = get_readed + # print self.inspect + if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? + nil + else + line + end + end + + def token + # require "tracer" + # Tracer.on + @prev_seek = @seek + @prev_line_no = @line_no + @prev_char_no = @char_no + begin + begin + tk = @OP.match(self) + @space_seen = tk.kind_of?(TkSPACE) + rescue SyntaxError + abort if @exception_on_syntax_error + tk = TkError.new(@seek, @line_no, @char_no) + end + end while @skip_space and tk.kind_of?(TkSPACE) + if @readed_auto_clean_up + get_readed + end + # Tracer.off + tk + end + + ENINDENT_CLAUSE = [ + "case", "class", "def", "do", "for", "if", + "module", "unless", "until", "while", "begin" #, "when" + ] + DEINDENT_CLAUSE = ["end" #, "when" + ] + + PERCENT_LTYPE = { + "q" => "\'", + "Q" => "\"", + "x" => "\`", + "r" => "\/", + "w" => "]" + } + + PERCENT_PAREN = { + "{" => "}", + "[" => "]", + "<" => ">", + "(" => ")" + } + + Ltype2Token = { + "\'" => TkSTRING, + "\"" => TkSTRING, + "\`" => TkXSTRING, + "\/" => TkREGEXP, + "]" => TkDSTRING + } + DLtype2Token = { + "\"" => TkDSTRING, + "\`" => TkDXSTRING, + "\/" => TkDREGEXP, + } + + def lex_init() + @OP = SLex.new + @OP.def_rules("\0", "\004", "\032") do + Token(TkEND_OF_SCRIPT) + end + + @OP.def_rules(" ", "\t", "\f", "\r", "\13") do + @space_seen = TRUE + while getc =~ /[ \t\f\r\13]/; end + ungetc + Token(TkSPACE) + end + + @OP.def_rule("#") do + |op, io| + identify_comment + end + + @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do + |op, io| + @ltype = "=" + until getc == "\n"; end + until peek_equal?("=end") && peek(4) =~ /\s/ + until getc == "\n"; end + end + getc; getc; getc; getc + @ltype = nil + Token(TkRD_COMMENT) + end + + @OP.def_rule("\n") do + print "\\n\n" if RubyLex.debug? + case @lex_state + when EXPR_BEG, EXPR_FNAME, EXPR_DOT + @continue = TRUE + else + @continue = FALSE + @lex_state = EXPR_BEG + end + @here_header = false + @here_readed = [] + Token(TkNL) + end + + @OP.def_rules("*", "**", + "!", "!=", "!~", + "=", "==", "===", + "=~", "<=>", + "<", "<=", + ">", ">=", ">>") do + |op, io| + @lex_state = EXPR_BEG + Token(op) + end + + @OP.def_rules("<<") do + |op, io| + if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && + (@lex_state != EXPR_ARG || @space_seen) + c = peek(0) + if /\S/ =~ c && (/["'`]/ =~ c || /[\w_]/ =~ c) + tk = identify_here_document; + end + else + tk = Token(op) + end + tk + end + + @OP.def_rules("'", '"') do + |op, io| + identify_string(op) + end + + @OP.def_rules("`") do + |op, io| + if @lex_state == EXPR_FNAME + Token(op) + else + identify_string(op) + end + end + + @OP.def_rules('?') do + |op, io| + if @lex_state == EXPR_END + @lex_state = EXPR_BEG + Token(TkQUESTION) + else + ch = getc + if @lex_state == EXPR_ARG && ch !~ /\s/ + ungetc + @lex_state = EXPR_BEG; + Token(TkQUESTION) + else + if (ch == '\\') + read_escape + end + @lex_state = EXPR_END + Token(TkINTEGER) + end + end + end + + @OP.def_rules("&", "&&", "|", "||") do + |op, io| + @lex_state = EXPR_BEG + Token(op) + end + + @OP.def_rules("+=", "-=", "*=", "**=", + "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do + |op, io| + @lex_state = EXPR_BEG + op =~ /^(.*)=$/ + Token(TkOPASGN, $1) + end + + @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do + Token(TkUPLUS) + end + + @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do + Token(TkUMINUS) + end + + @OP.def_rules("+", "-") do + |op, io| + catch(:RET) do + if @lex_state == EXPR_ARG + if @space_seen and peek(0) =~ /[0-9]/ + throw :RET, identify_number + else + @lex_state = EXPR_BEG + end + elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ + throw :RET, identify_number + else + @lex_state = EXPR_BEG + end + Token(op) + end + end + + @OP.def_rule(".") do + @lex_state = EXPR_BEG + if peek(0) =~ /[0-9]/ + ungetc + identify_number + else + # for obj.if + @lex_state = EXPR_DOT + Token(TkDOT) + end + end + + @OP.def_rules("..", "...") do + |op, io| + @lex_state = EXPR_BEG + Token(op) + end + + lex_int2 + end + + def lex_int2 + @OP.def_rules("]", "}", ")") do + |op, io| + @lex_state = EXPR_END + @indent -= 1 + Token(op) + end + + @OP.def_rule(":") do + if @lex_state == EXPR_END || peek(0) =~ /\s/ + @lex_state = EXPR_BEG + Token(TkCOLON) + else + @lex_state = EXPR_FNAME; + Token(TkSYMBEG) + end + end + + @OP.def_rule("::") do +# p @lex_state.id2name, @space_seen + if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen + @lex_state = EXPR_BEG + Token(TkCOLON3) + else + @lex_state = EXPR_DOT + Token(TkCOLON2) + end + end + + @OP.def_rule("/") do + |op, io| + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + identify_string(op) + elsif peek(0) == '=' + getc + @lex_state = EXPR_BEG + Token(TkOPASGN, :/) #/) + elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_string(op) + else + @lex_state = EXPR_BEG + Token("/") #/) + end + end + + @OP.def_rules("^") do + @lex_state = EXPR_BEG + Token("^") + end + + # @OP.def_rules("^=") do + # @lex_state = EXPR_BEG + # Token(OP_ASGN, :^) + # end + + @OP.def_rules(",", ";") do + |op, io| + @lex_state = EXPR_BEG + Token(op) + end + + @OP.def_rule("~") do + @lex_state = EXPR_BEG + Token("~") + end + + @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do + @lex_state = EXPR_BEG + Token("~") + end + + @OP.def_rule("(") do + @indent += 1 + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + @lex_state = EXPR_BEG + Token(TkfLPAREN) + else + @lex_state = EXPR_BEG + Token(TkLPAREN) + end + end + + @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do + Token("[]") + end + + @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do + Token("[]=") + end + + @OP.def_rule("[") do + @indent += 1 + if @lex_state == EXPR_FNAME + Token(TkfLBRACK) + else + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + t = Token(TkLBRACK) + elsif @lex_state == EXPR_ARG && @space_seen + t = Token(TkLBRACK) + else + t = Token(TkfLBRACK) + end + @lex_state = EXPR_BEG + t + end + end + + @OP.def_rule("{") do + @indent += 1 + if @lex_state != EXPR_END && @lex_state != EXPR_ARG + t = Token(TkLBRACE) + else + t = Token(TkfLBRACE) + end + @lex_state = EXPR_BEG + t + end + + @OP.def_rule('\\') do + if getc == "\n" + @space_seen = true + @continue = true + Token(TkSPACE) + else + ungetc + Token("\\") + end + end + + @OP.def_rule('%') do + |op, io| + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + identify_quotation + elsif peek(0) == '=' + getc + Token(OP_ASGIN, "%") + elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_quotation + else + @lex_state = EXPR_BEG + Token("%") #)) + end + end + + @OP.def_rule('$') do + identify_gvar + end + + @OP.def_rule('@') do + if peek(0) =~ /[\w_]/ + ungetc + identify_identifier + else + Token("@") + end + end + + # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do + # |op, io| + # @indent += 1 + # @lex_state = EXPR_FNAME + # # @lex_state = EXPR_END + # # until @rests[0] == "\n" or @rests[0] == ";" + # # rests.shift + # # end + # end + + @OP.def_rule("") do + |op, io| + printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug? + if peek(0) =~ /[0-9]/ + t = identify_number + elsif peek(0) =~ /[\w_]/ + t = identify_identifier + end + printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug? + t + end + + p @OP if RubyLex.debug? + end + + def identify_gvar + @lex_state = EXPR_END + + case ch = getc + when /[~_*$?!@/\\;,=:<>".]/ #" + Token(TkGVAR, "$" + ch) + when "-" + Token(TkGVAR, "$-" + getc) + when "&", "`", "'", "+" + Token(TkBACK_REF, "$"+ch) + when /[1-9]/ + while getc =~ /[0-9]/; end + ungetc + Token(TkNTH_REF) + when /\w/ + ungetc + ungetc + identify_identifier + else + ungetc + Token("$") + end + end + + def identify_identifier + token = "" + token.concat getc if peek(0) =~ /[$@]/ + while (ch = getc) =~ /\w|_/ + print ":", ch, ":" if RubyLex.debug? + token.concat ch + end + ungetc + + if ch == "!" or ch == "?" + token.concat getc + end + # fix token + + case token + when /^\$/ + return Token(TkGVAR, token) + when /^\@/ + @lex_state = EXPR_END + return Token(TkIVAR, token) + end + + if @lex_state != EXPR_DOT + print token, "\n" if RubyLex.debug? + + token_c, *trans = TkReading2Token[token] + if token_c + # reserved word? + + if (@lex_state != EXPR_BEG && + @lex_state != EXPR_FNAME && + trans[1]) + # modifiers + token_c = TkSymbol2Token[trans[1]] + @lex_state = trans[0] + else + if @lex_state != EXPR_FNAME + if ENINDENT_CLAUSE.include?(token) + @indent += 1 + elsif DEINDENT_CLAUSE.include?(token) + @indent -= 1 + end + @lex_state = trans[0] + else + @lex_state = EXPR_END + end + end + return Token(token_c, token) + end + end + + if @lex_state == EXPR_FNAME + @lex_state = EXPR_END + if peek(0) == '=' + token.concat getc + end + elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT + @lex_state = EXPR_ARG + else + @lex_state = EXPR_END + end + + if token[0, 1] =~ /[A-Z]/ + return Token(TkCONSTANT, token) + elsif token[token.size - 1, 1] =~ /[!?]/ + return Token(TkFID, token) + else + return Token(TkIDENTIFIER, token) + end + end + + def identify_here_document + ch = getc + if lt = PERCENT_LTYPE[ch] + quoted = "" + while (c = getc) && c != lt + quoted.concat c + end + else + lt = '"' + quoted = ch.dup + while (c = getc) && c =~ /\w/ + quoted.concat c + end + ungetc + end + + ltback, @ltype = @ltype, lt + reserve = [] + while ch = getc + reserve.push ch + if ch == "\\" + reserve.push ch = getc + elsif ch == "\n" + break + end + end + + @here_header = false + while (l = gets.chomp) && l != quoted + end + + @here_header = true + @here_readed.concat reserve + while ch = reserve.pop + ungetc ch + end + + @ltype = ltback + @lex_state = EXPR_END + Token(Ltype2Token[lt]) + end + + def identify_quotation + ch = getc + if lt = PERCENT_LTYPE[ch] + ch = getc + elsif ch =~ /\W/ + lt = "\"" + else + RubyLex.fail SyntaxError, "unknown type of %string" + end +# if ch !~ /\W/ +# ungetc +# next +# end + #@ltype = lt + @quoted = ch unless @quoted = PERCENT_PAREN[ch] + identify_string(lt, @quoted) + end + + def identify_number + @lex_state = EXPR_END + + if ch = getc + if peek(0) == "x" + ch = getc + match = /[0-9a-f_]/ + else + match = /[0-7_]/ + end + while ch = getc + if ch !~ match + ungetc + break + end + end + return Token(TkINTEGER) + end + + type = TkINTEGER + allow_point = TRUE + allow_e = TRUE + while ch = getc + case ch + when /[0-9_]/ + when allow_point && "." + type = TkFLOAT + if peek(0) !~ /[0-9]/ + ungetc + break + end + allow_point = false + when allow_e && "e", allow_e && "E" + type = TkFLOAT + if peek(0) =~ /[+-]/ + getc + end + allow_e = false + allow_point = false + else + ungetc + break + end + end + Token(type) + end + + def identify_string(ltype, quoted = ltype) + @ltype = ltype + @quoted = quoted + subtype = nil + begin + while ch = getc + if @quoted == ch + break + elsif @ltype != "'" && @ltype != "]" and ch == "#" + subtype = true + elsif ch == '\\' #' + read_escape + end + end + if @ltype == "/" + if peek(0) =~ /i|o|n|e|s/ + getc + end + end + if subtype + Token(DLtype2Token[ltype]) + else + Token(Ltype2Token[ltype]) + end + ensure + @ltype = nil + @quoted = nil + @lex_state = EXPR_END + end + end + + def identify_comment + @ltype = "#" + + while ch = getc + if ch == "\\" #" + read_escape + end + if ch == "\n" + @ltype = nil + ungetc + break + end + end + return Token(TkCOMMENT) + end + + def read_escape + case ch = getc + when "\n", "\r", "\f" + when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #" + when /[0-7]/ + ungetc ch + 3.times do + case ch = getc + when /[0-7]/ + when nil + break + else + ungetc + break + end + end + + when "x" + 2.times do + case ch = getc + when /[0-9a-fA-F]/ + when nil + break + else + ungetc + break + end + end + + when "M" + if (ch = getc) != '-' + ungetc + else + if (ch = getc) == "\\" #" + read_escape(chrs) + end + end + + when "C", "c", "^" + if ch == "C" and (ch = getc) != "-" + ungetc + elsif (ch = getc) == "\\" #" + read_escape(chrs) + end + else + # other characters + end + end +end diff --git a/lib/irb/ruby-token.rb b/lib/irb/ruby-token.rb new file mode 100644 index 0000000000..1532dc78eb --- /dev/null +++ b/lib/irb/ruby-token.rb @@ -0,0 +1,266 @@ +# +# ruby-token.rb - ruby tokens +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# +module RubyToken + EXPR_BEG = :EXPR_BEG + EXPR_MID = :EXPR_MID + EXPR_END = :EXPR_END + EXPR_ARG = :EXPR_ARG + EXPR_FNAME = :EXPR_FNAME + EXPR_DOT = :EXPR_DOT + EXPR_CLASS = :EXPR_CLASS + + class Token + def initialize(seek, line_no, char_no) + @seek = seek + @line_no = line_no + @char_no = char_no + end + attr :seek + attr :line_no + attr :char_no + end + + class TkNode < Token + def initialize(seek, line_no, char_no) + super + end + attr :node + end + + class TkId < Token + def initialize(seek, line_no, char_no, name) + super(seek, line_no, char_no) + @name = name + end + attr :name + end + + class TkVal < Token + def initialize(seek, line_no, char_no, value = nil) + super(seek, line_no, char_no) + @value = value + end + attr :value + end + + class TkOp < Token + attr :name, true + end + + class TkOPASGN < TkOp + def initialize(seek, line_no, char_no, op) + super(seek, line_no, char_no) + op = TkReading2Token[op] unless op.kind_of?(Symbol) + @op = op + end + attr :op + end + + class TkUnknownChar < Token + def initialize(seek, line_no, char_no, id) + super(seek, line_no, char_no) + @name = name + end + attr :name + end + + class TkError < Token + end + + def Token(token, value = nil) + case token + when String + if (tk = TkReading2Token[token]).nil? + IRB.fail TkReading2TokenNoKey, token + end + tk = Token(tk[0], value) + if tk.kind_of?(TkOp) + tk.name = token + end + return tk + when Symbol + if (tk = TkSymbol2Token[token]).nil? + IRB.fail TkSymbol2TokenNoKey, token + end + return Token(tk[0], value) + else + if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty? + token.new(@prev_seek, @prev_line_no, @prev_char_no) + else + token.new(@prev_seek, @prev_line_no, @prev_char_no, value) + end + end + end + + TokenDefinitions = [ + [:TkCLASS, TkId, "class", EXPR_CLASS], + [:TkMODULE, TkId, "module", EXPR_BEG], + [:TkDEF, TkId, "def", EXPR_FNAME], + [:TkUNDEF, TkId, "undef", EXPR_FNAME], + [:TkBEGIN, TkId, "begin", EXPR_BEG], + [:TkRESCUE, TkId, "rescue", EXPR_MID], + [:TkENSURE, TkId, "ensure", EXPR_BEG], + [:TkEND, TkId, "end", EXPR_END], + [:TkIF, TkId, "if", EXPR_BEG, :TkIF_MOD], + [:TkUNLESS, TkId, "unless", EXPR_BEG, :TkUNLESS_MOD], + [:TkTHEN, TkId, "then", EXPR_BEG], + [:TkELSIF, TkId, "elsif", EXPR_BEG], + [:TkELSE, TkId, "else", EXPR_BEG], + [:TkCASE, TkId, "case", EXPR_BEG], + [:TkWHEN, TkId, "when", EXPR_BEG], + [:TkWHILE, TkId, "while", EXPR_BEG, :TkWHILE_MOD], + [:TkUNTIL, TkId, "until", EXPR_BEG, :TkUNTIL_MOD], + [:TkFOR, TkId, "for", EXPR_BEG], + [:TkBREAK, TkId, "break", EXPR_END], + [:TkNEXT, TkId, "next", EXPR_END], + [:TkREDO, TkId, "redo", EXPR_END], + [:TkRETRY, TkId, "retry", EXPR_END], + [:TkIN, TkId, "in", EXPR_BEG], + [:TkDO, TkId, "do", EXPR_BEG], + [:TkRETURN, TkId, "return", EXPR_MID], + [:TkYIELD, TkId, "yield", EXPR_END], + [:TkSUPER, TkId, "super", EXPR_END], + [:TkSELF, TkId, "self", EXPR_END], + [:TkNIL, TkId, "nil", EXPR_END], + [:TkTRUE, TkId, "true", EXPR_END], + [:TkFALSE, TkId, "false", EXPR_END], + [:TkAND, TkId, "and", EXPR_BEG], + [:TkOR, TkId, "or", EXPR_BEG], + [:TkNOT, TkId, "not", EXPR_BEG], + [:TkIF_MOD, TkId], + [:TkUNLESS_MOD, TkId], + [:TkWHILE_MOD, TkId], + [:TkUNTIL_MOD, TkId], + [:TkALIAS, TkId, "alias", EXPR_FNAME], + [:TkDEFINED, TkId, "defined?", EXPR_END], + [:TklBEGIN, TkId, "BEGIN", EXPR_END], + [:TklEND, TkId, "END", EXPR_END], + [:Tk__LINE__, TkId, "__LINE__", EXPR_END], + [:Tk__FILE__, TkId, "__FILE__", EXPR_END], + + [:TkIDENTIFIER, TkId], + [:TkFID, TkId], + [:TkGVAR, TkId], + [:TkIVAR, TkId], + [:TkCONSTANT, TkId], + + [:TkINTEGER, TkVal], + [:TkFLOAT, TkVal], + [:TkSTRING, TkVal], + [:TkXSTRING, TkVal], + [:TkREGEXP, TkVal], + + [:TkDSTRING, TkNode], + [:TkDXSTRING, TkNode], + [:TkDREGEXP, TkNode], + [:TkNTH_REF, TkNode], + [:TkBACK_REF, TkNode], + + [:TkUPLUS, TkOp, "+@"], + [:TkUMINUS, TkOp, "-@"], + [:TkPOW, TkOp, "**"], + [:TkCMP, TkOp, "<=>"], + [:TkEQ, TkOp, "=="], + [:TkEQQ, TkOp, "==="], + [:TkNEQ, TkOp, "!="], + [:TkGEQ, TkOp, ">="], + [:TkLEQ, TkOp, "<="], + [:TkANDOP, TkOp, "&&"], + [:TkOROP, TkOp, "||"], + [:TkMATCH, TkOp, "=~"], + [:TkNMATCH, TkOp, "!~"], + [:TkDOT2, TkOp, ".."], + [:TkDOT3, TkOp, "..."], + [:TkAREF, TkOp, "[]"], + [:TkASET, TkOp, "[]="], + [:TkLSHFT, TkOp, "<<"], + [:TkRSHFT, TkOp, ">>"], + [:TkCOLON2, TkOp], + [:TkCOLON3, TkOp], +# [:OPASGN, TkOp], # +=, -= etc. # + [:TkASSOC, TkOp, "=>"], + [:TkQUESTION, TkOp, "?"], #? + [:TkCOLON, TkOp, ":"], #: + + [:TkfLPAREN], # func( # + [:TkfLBRACK], # func[ # + [:TkfLBRACE], # func{ # + [:TkSTAR], # *arg + [:TkAMPER], # &arg # + [:TkSYMBEG], # :SYMBOL + + [:TkGT, TkOp, ">"], + [:TkLT, TkOp, "<"], + [:TkPLUS, TkOp, "+"], + [:TkMINUS, TkOp, "-"], + [:TkMULT, TkOp, "*"], + [:TkDIV, TkOp, "/"], + [:TkMOD, TkOp, "%"], + [:TkBITOR, TkOp, "|"], + [:TkBITXOR, TkOp, "^"], + [:TkBITAND, TkOp, "&"], + [:TkBITNOT, TkOp, "~"], + [:TkNOTOP, TkOp, "!"], + + [:TkBACKQUOTE, TkOp, "`"], + + [:TkASSGIN, Token, "="], + [:TkDOT, Token, "."], + [:TkLPAREN, Token, "("], #(exp) + [:TkLBRACK, Token, "["], #[arry] + [:TkLBRACE, Token, "{"], #{hash} + [:TkRPAREN, Token, ")"], + [:TkRBRACK, Token, "]"], + [:TkRBRACE, Token, "}"], + [:TkCOMMA, Token, ","], + [:TkSEMICOLON, Token, ";"], + + [:TkCOMMENT], + [:TkRD_COMMENT], + [:TkSPACE], + [:TkNL], + [:TkEND_OF_SCRIPT], + + [:TkBACKSLASH, TkUnknownChar, "\\"], + [:TkAT, TkUnknownChar, "@"], + [:TkDOLLAR, TkUnknownChar, "$"], + ] + + # {reading => token_class} + # {reading => [token_class, *opt]} + TkReading2Token = {} + TkSymbol2Token = {} + + def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) + token_n = token_n.id2name unless token_n.kind_of?(String) + if RubyToken.const_defined?(token_n) + IRB.fail AlreadyDefinedToken, token_n + end + token_c = eval("class #{token_n} < #{super_token}; end; #{token_n}") + + if reading + if TkReading2Token[reading] + IRB.fail TkReading2TokenDuplicateError, token_n, reading + end + if opts.empty? + TkReading2Token[reading] = [token_c] + else + TkReading2Token[reading] = [token_c].concat(opts) + end + end + TkSymbol2Token[token_n.intern] = token_c + end + + for defs in TokenDefinitions + def_token(*defs) + end +end diff --git a/lib/irb/slex.rb b/lib/irb/slex.rb new file mode 100644 index 0000000000..85aa92bd73 --- /dev/null +++ b/lib/irb/slex.rb @@ -0,0 +1,279 @@ +# +# irb-slex.rb - symple lex analizer +# $Release Version: 0.6$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +require "e2mmap" + +class SLex + @RCS_ID='-$Id$-' + + extend Exception2MessageMapper + def_exception :ErrNodeNothing, "node nothing" + def_exception :ErrNodeAlreadyExists, "node already exists" + + class << self + attr :debug_level, TRUE + def debug? + debug_level > 0 + end + end + @debug_level = 0 + + def initialize + @head = Node.new("") + end + + def def_rule(token, preproc = nil, postproc = nil) + # print node.inspect, "\n" if SLex.debug? + postproc = proc if iterator? + node = create(token, preproc, postproc) + end + + def def_rules(*tokens) + if iterator? + p = proc + end + for token in tokens + def_rule(token, nil, p) + end + end + + def preporc(token, proc) + node = search(token) + node.preproc=proc + end + + def postproc(token) + node = search(token, proc) + node.postproc=proc + end + + def search(token) + @head.search(token.split(//)) + end + + def create(token, preproc = nil, postproc = nil) + @head.create_subnode(token.split(//), preproc, postproc) + end + + def match(token) + case token + when Array + when String + token = token.split(//) + match(token.split(//)) + else + return @head.match_io(token) + end + ret = @head.match(token) + printf "match end: %s:%s", ret, token.inspect if SLex.debug? + ret + end + + def inspect + format("", @head.inspect) + end + + #---------------------------------------------------------------------- + # + # class Node - + # + #---------------------------------------------------------------------- + class Node + # if postproc no exist, this node is abstract node. + # if postproc isn't nil, this node is real node. + def initialize(preproc = nil, postproc = nil) + @Tree = {} + @preproc = preproc + @postproc = postproc + end + + attr :preproc, TRUE + attr :postproc, TRUE + + def search(chrs, opt = nil) + return self if chrs.empty? + ch = chrs.shift + if node = @Tree[ch] + node.search(chrs, opt) + else + if opt + chrs.unshift ch + self.create_subnode(chrs) + else + SLex.fail ErrNodeNothing + end + end + end + + def create_subnode(chrs, preproc = nil, postproc = nil) + if chrs.empty? + if @postproc + p node + SLex.fail ErrNodeAlreadyExists + else + print "Warn: change abstruct node to real node\n" if SLex.debug? + @preproc = preproc + @postproc = postproc + end + return self + end + + ch = chrs.shift + if node = @Tree[ch] + if chrs.empty? + if node.postproc + p node + p self + p ch + p chrs + SLex.fail ErrNodeAlreadyExists + else + print "Warn: change abstruct node to real node\n" if SLex.debug? + node.preproc = preproc + node.postproc = postproc + end + else + node.create_subnode(chrs, preproc, postproc) + end + else + if chrs.empty? + node = Node.new(preproc, postproc) + else + node = Node.new + node.create_subnode(chrs, preproc, postproc) + end + @Tree[ch] = node + end + node + end + + # + # chrs: String + # character array + # io It must have getc()/ungetc(), and ungetc() can be + # called any number of times. + # + def match(chrs, op = "") + print "match>: ", chrs, "op:", op, "\n" if SLex.debug? + if chrs.empty? + if @preproc.nil? || @preproc.call(op, chrs) + printf "op1: %s\n", op if SLex.debug? + @postproc.call(op, chrs) + else + nil + end + else + ch = chrs.shift + if node = @Tree[ch] + if ret = node.match(chrs, op+ch) + return ret + else + chrs.unshift ch + if @postproc and @preproc.nil? || @preproc.call(op, chrs) + printf "op2: %s\n", op.inspect if SLex.debug? + ret = @postproc.call(op, chrs) + return ret + else + return nil + end + end + else + chrs.unshift ch + if @postproc and @preproc.nil? || @preproc.call(op, chrs) + printf "op3: %s\n", op if SLex.debug? + @postproc.call(op, chrs) + return "" + else + return nil + end + end + end + end + + def match_io(io, op = "") + if op == "" + ch = io.getc + if ch == nil + return nil + end + else + ch = io.getc_of_rests + end + if ch.nil? + if @preproc.nil? || @preproc.call(op, io) + printf "op1: %s\n", op if SLex.debug? + @postproc.call(op, io) + else + nil + end + else + if node = @Tree[ch] + if ret = node.match_io(io, op+ch) + ret + else + io.ungetc ch + if @postproc and @preproc.nil? || @preproc.call(op, io) + printf "op2: %s\n", op.inspect if SLex.debug? + @postproc.call(op, io) + else + nil + end + end + else + io.ungetc ch + if @postproc and @preproc.nil? || @preproc.call(op, io) + printf "op3: %s\n", op if SLex.debug? + @postproc.call(op, io) + else + nil + end + end + end + end + end +end + +if $0 == __FILE__ + # Tracer.on + case $1 + when "1" + tr = SLex.new + print "0: ", tr.inspect, "\n" + tr.def_rule("=") {print "=\n"} + print "1: ", tr.inspect, "\n" + tr.def_rule("==") {print "==\n"} + print "2: ", tr.inspect, "\n" + + print "case 1:\n" + print tr.match("="), "\n" + print "case 2:\n" + print tr.match("=="), "\n" + print "case 3:\n" + print tr.match("=>"), "\n" + + when "2" + tr = SLex.new + print "0: ", tr.inspect, "\n" + tr.def_rule("=") {print "=\n"} + print "1: ", tr.inspect, "\n" + tr.def_rule("==", proc{FALSE}) {print "==\n"} + print "2: ", tr.inspect, "\n" + + print "case 1:\n" + print tr.match("="), "\n" + print "case 2:\n" + print tr.match("=="), "\n" + print "case 3:\n" + print tr.match("=>"), "\n" + end + exit +end diff --git a/lib/irb/version.rb b/lib/irb/version.rb new file mode 100644 index 0000000000..7179d1c163 --- /dev/null +++ b/lib/irb/version.rb @@ -0,0 +1,16 @@ +# +# version.rb - irb version definition file +# $Release Version: 0.6.1$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +module IRB + @RELEASE_VERSION = "0.6.1" + @LAST_UPDATE_DATE = "99/09/16" +end diff --git a/lib/irb/workspace-binding-2.rb b/lib/irb/workspace-binding-2.rb new file mode 100644 index 0000000000..d005296f6e --- /dev/null +++ b/lib/irb/workspace-binding-2.rb @@ -0,0 +1,15 @@ +# +# bind.rb - +# $Release Version: $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +while true + IRB::BINDING_QUEUE.push b = binding +end diff --git a/lib/irb/workspace-binding.rb b/lib/irb/workspace-binding.rb new file mode 100644 index 0000000000..d58088d9dd --- /dev/null +++ b/lib/irb/workspace-binding.rb @@ -0,0 +1,77 @@ +# +# workspace-binding.rb - +# $Release Version: $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + + +module IRB + # create new workspace. + def IRB.workspace_binding(*main) + if @CONF[:SINGLE_IRB] + bind = TOPLEVEL_BINDING + else + case @CONF[:CONTEXT_MODE] + when 0 + bind = eval("proc{binding}.call", + TOPLEVEL_BINDING, + "(irb_local_binding)", + 1) + when 1 + require "tempfile" + f = Tempfile.open("irb-binding") + f.print <num_entries, arg->arg); st_foreach(tbl, obj_each, arg); diff --git a/pack.c b/pack.c index cd24093683..757d841fcc 100644 --- a/pack.c +++ b/pack.c @@ -843,6 +843,53 @@ pack_pack(ary, fmt) } break; + case 'w': + while (len-- > 0) { + unsigned long ul; + VALUE buf = rb_str_new(0, 0); + char c, *bufs, *bufe; + + from = NEXTFROM; + + if (TYPE(from) == T_BIGNUM) { + VALUE big128 = rb_uint2big(128); + while (TYPE(from) == T_BIGNUM) { + from = rb_big_divmod(from, big128); + c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80; /* mod */ + rb_str_cat(buf, &c, sizeof(char)); + from = RARRAY(from)->ptr[0]; /* div */ + } + } + + if (NIL_P(from)) ul = 0; + else { + ul = NUM2ULONG(from); + } + + while (ul) { + c = ((ul & 0x7f) | 0x80); + rb_str_cat(buf, &c, sizeof(char)); + ul >>= 7; + } + + if (RSTRING(buf)->len) { + bufs = RSTRING(buf)->ptr; + bufe = bufs + RSTRING(buf)->len - 1; + *bufs &= 0x7f; /* clear continue bit */ + while (bufs < bufe) { /* reverse */ + c = *bufs; + *bufs++ = *bufe; + *bufe-- = c; + } + rb_str_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len); + } + else { + c = 0; + rb_str_cat(res, &c, sizeof(char)); + } + } + break; + default: break; } @@ -1573,6 +1620,37 @@ pack_unpack(str, fmt) } break; + case 'w': + { + unsigned long ul = 0; + unsigned long ulmask = 0xfe << ((sizeof(unsigned long) - 1) * 8); + + while (len > 0 && s < send) { + ul <<= 7; + ul |= (*s & 0x7f); + if (!(*s++ & 0x80)) { + rb_ary_push(ary, rb_uint2inum(ul)); + len--; + ul = 0; + } + else if (ul & ulmask) { + VALUE big = rb_uint2big(ul); + VALUE big128 = rb_uint2big(128); + while (s < send) { + big = rb_big_mul(big, big128); + big = rb_big_plus(big, rb_uint2big(*s & 0x7f)); + if (!(*s++ & 0x80)) { + rb_ary_push(ary, big); + len--; + ul = 0; + break; + } + } + } + } + } + break; + default: break; } diff --git a/parse.y b/parse.y index 6c5aaa7c9d..a34c5aabf3 100644 --- a/parse.y +++ b/parse.y @@ -2124,6 +2124,84 @@ read_escape() } } +static int +tokadd_escape() +{ + int c; + + switch (c = nextc()) { + case '\n': + return 0; /* just ignore */ + + case '0': case '1': case '2': case '3': /* octal constant */ + case '4': case '5': case '6': case '7': + { + int i; + + tokadd('\\'); + tokadd(c); + for (i=0; i<2; i++) { + c = nextc(); + if (c == -1) goto eof; + if (c < '0' || '7' < c) { + pushback(c); + break; + } + tokadd(c); + } + } + return 0; + + case 'x': /* hex constant */ + { + int numlen; + + scan_hex(lex_p, 2, &numlen); + while (numlen--) + tokadd(nextc()); + } + return 0; + + case 'M': + if ((c = nextc()) != '-') { + yyerror("Invalid escape character syntax"); + pushback(c); + return 0; + } + tokadd('\\'); tokadd('M'); tokadd('-'); + goto escaped; + + case 'C': + if ((c = nextc()) != '-') { + yyerror("Invalid escape character syntax"); + pushback(c); + return 0; + } + tokadd('\\'); tokadd('C'); tokadd('-'); + goto escaped; + + case 'c': + tokadd('\\'); tokadd('c'); + escaped: + if ((c = nextc()) == '\\') { + return tokadd_escape(); + } + else if (c == -1) goto eof; + tokadd(c); + return 0; + + eof: + case -1: + yyerror("Invalid escape character syntax"); + return -1; + + default: + tokadd('\\'); + tokadd(c); + } + return 0; +} + static int parse_regx(term, paren) int term, paren; @@ -2133,78 +2211,31 @@ parse_regx(term, paren) int once = 0; int nest = 0; int options = 0; - int in_brack = 0; int re_start = ruby_sourceline; NODE *list = 0; newtok(); while ((c = nextc()) != -1) { - if (!in_brack && c == term && nest == 0) { + if (c == term && nest == 0) { goto regx_end; } switch (c) { - case '[': - in_brack = 1; - break; - case ']': - in_brack = 0; - break; - case '#': list = str_extend(list, term); if (list == (NODE*)-1) return 0; continue; case '\\': - switch (c = nextc()) { - case -1: - ruby_sourceline = re_start; - rb_compile_error("unterminated regexp meets end of file"); + if (tokadd_escape() < 0) return 0; - - case '\n': - break; - - case '\\': - case '^': - case 's': - tokadd('\\'); - tokadd(c); - break; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - case '0': case 'x': - tokadd('\\'); - tokadd(c); - break; - - case 'b': - if (!in_brack) { - tokadd('\\'); - tokadd('b'); - break; - } - /* fall through */ - default: - if (c == term) { - tokadd(c); - } - else { - tokadd('\\'); - tokadd(c); - } - } continue; case -1: - rb_compile_error("unterminated regexp"); - return 0; + goto unterminated; default: - if (paren && !in_brack) { + if (paren) { if (c == paren) nest++; if (c == term) nest--; } @@ -2272,7 +2303,9 @@ parse_regx(term, paren) } tokadd(c); } - rb_compile_error("unterminated regexp"); + unterminated: + ruby_sourceline = re_start; + rb_compile_error("unterminated regexp meets end of file"); return 0; } diff --git a/regex.c b/regex.c index 9ddc4752de..91fc1d98c1 100644 --- a/regex.c +++ b/regex.c @@ -22,13 +22,11 @@ /* UTF-8 extension added Jan 16 1999 by Yoshida Masato */ #include "config.h" -#ifdef RUBY_PLATFORM -# define RUBY -extern int rb_prohibit_interrupt; -extern int rb_trap_pending; -# define CHECK_INTS if (!rb_prohibit_interrupt) {\ - if (rb_trap_pending) rb_trap_exec();\ -} + +#ifdef HAVE_STRING_H +# include +#else +# include #endif /* We write fatal error messages on standard error. */ @@ -63,6 +61,17 @@ extern int rb_trap_pending; # define _(args) () #endif +#ifdef RUBY_PLATFORM +# define RUBY +extern int rb_prohibit_interrupt; +extern int rb_trap_pending; +void rb_trap_exec _((void)); + +# define CHECK_INTS if (!rb_prohibit_interrupt) {\ + if (rb_trap_pending) rb_trap_exec();\ +} +#endif + #ifndef xmalloc void *xmalloc _((size_t)); void *xcalloc _((size_t,size_t)); @@ -70,7 +79,7 @@ void *xrealloc _((void*,size_t)); void free _((void*)); #endif -#define NO_ALLOCA /* /* try it out for now */ +#define NO_ALLOCA /* try it out for now */ #ifndef NO_ALLOCA /* Make alloca work the best possible way. */ #ifdef __GNUC__ @@ -474,7 +483,7 @@ utf8_firstbyte(c) static void print_mbc(c) - unsigned long c; + unsigned int c; { if (current_mbctype == MBCTYPE_UTF8) { if (c < 0x80) @@ -587,13 +596,13 @@ print_mbc(c) } while (0) #define EXTRACT_MBC(p) \ - ((unsigned long)((unsigned char)(p)[0] << 24 | \ + ((unsigned int)((unsigned char)(p)[0] << 24 | \ (unsigned char)(p)[1] << 16 | \ (unsigned char)(p)[2] << 8 | \ (unsigned char)(p)[3])) #define EXTRACT_MBC_AND_INCR(p) \ - ((unsigned long)((p) += 4, \ + ((unsigned int)((p) += 4, \ (unsigned char)(p)[-4] << 24 | \ (unsigned char)(p)[-3] << 16 | \ (unsigned char)(p)[-2] << 8 | \ @@ -1398,12 +1407,6 @@ re_compile_pattern(pattern, size, bufp) had_num_literal = 0; had_char_class = 0; - /* charset_not matches newline according to a syntax bit. */ - if ((enum regexpcode)b[-2] == charset_not) { - if (bufp->options & RE_OPTION_POSIXLINE) - SET_LIST_BIT ('\n'); - } - /* Read in characters and ranges, setting map bits. */ for (;;) { int size; @@ -2325,6 +2328,8 @@ re_compile_pattern(pattern, size, bufp) case dummy_failure_jump: bufp->options |= RE_OPTIMIZE_ANCHOR; break; + default: + break; } } else if (*laststart == charset || *laststart == charset_not) { @@ -3004,6 +3009,7 @@ re_compile_fastmap(bufp) } break; + case begpos: case unused: /* pacify gcc -Wall */ break; } @@ -4247,7 +4253,6 @@ re_match(bufp, string_arg, size, pos, regs) p1 = p; /* If failed to a backwards jump that's part of a repetition loop, need to pop this failure point and use the next one. */ - pop_loop: switch ((enum regexpcode)*p1) { case jump_n: case finalize_push_n: diff --git a/ruby.c b/ruby.c index 0777ffd574..326c98d2d4 100644 --- a/ruby.c +++ b/ruby.c @@ -291,7 +291,7 @@ static char* moreswitches(s) char *s; { - int argc; char *argv[3]; char **argvp = argv; + int argc; char *argv[3]; char *p = s; argc = 2; argv[0] = argv[2] = 0; @@ -636,6 +636,12 @@ proc_options(argc, argv) load_file(script, 1); } + if (rb_safe_level() == 0) { + rb_ary_push(rb_load_path, rb_str_new2(".")); + addpath(getenv("RUBYLIB")); + } + + process_sflag(); xflag = 0; } @@ -917,10 +923,6 @@ ruby_prog_init() rb_define_readonly_variable("$-p", &do_print); rb_define_readonly_variable("$-l", &do_line); - if (rb_safe_level() == 0) { - addpath("."); - } - addpath(RUBY_LIB); #if defined(_WIN32) || defined(DJGPP) addpath(ruby_libpath()); @@ -942,10 +944,6 @@ ruby_prog_init() addpath(RUBY_SEARCH_PATH); #endif - if (rb_safe_level() == 0) { - addpath(getenv("RUBYLIB")); - } - rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0); rb_argv = rb_ary_new(); diff --git a/ruby.h b/ruby.h index 1c50d35bb4..149ca98557 100644 --- a/ruby.h +++ b/ruby.h @@ -358,13 +358,13 @@ struct RBignum { #define FL_ABLE(x) (!SPECIAL_CONST_P(x)) #define FL_TEST(x,f) (FL_ABLE(x)?(RBASIC(x)->flags&(f)):0) -#define FL_SET(x,f) (FL_ABLE(x) && (RBASIC(x)->flags |= (f))) -#define FL_UNSET(x,f) (FL_ABLE(x) && (RBASIC(x)->flags &= ~(f))) -#define FL_REVERSE(x,f) (FL_ABLE(x) && (RBASIC(x)->flags ^= (f))) +#define FL_SET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags |= (f);} while (0) +#define FL_UNSET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags &= ~(f);} while (0) +#define FL_REVERSE(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags ^= (f);} while (0) #define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT) #define OBJ_TAINT(x) FL_SET((x), FL_TAINT) -#define OBJ_INFECT(x,s) (FL_ABLE(x) && FL_ABLE(s) && (RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT)) +#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0) #define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) @@ -394,8 +394,8 @@ void rb_define_variable _((const char*,VALUE*)); void rb_define_virtual_variable _((const char*,VALUE(*)(),void(*)())); void rb_define_hooked_variable _((const char*,VALUE*,VALUE(*)(),void(*)())); void rb_define_readonly_variable _((const char*,VALUE*)); -void rb_define_constants _((VALUE,const char*,VALUE)); -void rb_define_global_constants _((const char*,VALUE)); +void rb_define_const _((VALUE,const char*,VALUE)); +void rb_define_global_const _((const char*,VALUE)); void rb_define_method _((VALUE,const char*,VALUE(*)(),int)); void rb_define_module_function _((VALUE,const char*,VALUE(*)(),int)); diff --git a/sample/irb.rb b/sample/irb.rb new file mode 100644 index 0000000000..38d184dfd0 --- /dev/null +++ b/sample/irb.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# +# irb.rb - intaractive ruby +# $Release Version: 0.6 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# Usage: +# +# irb.rb [options] file_name opts +# +# + +require "irb/main" + +if __FILE__ == $0 + IRB.start(__FILE__) +else + # check -e option + tmp = ENV["TMP"] || ENV["TMPDIR"] || "/tmp" + if %r|#{tmp}/rb| =~ $0 + IRB.start(__FILE__) + else + IRB.initialize(__FILE__) + end +end diff --git a/sample/rbc.rb b/sample/rbc.rb index 9f1ab9443d..2c18d823a1 100644 --- a/sample/rbc.rb +++ b/sample/rbc.rb @@ -413,7 +413,7 @@ module BC_APPLICATION__ ch = chrs.shift case ch - when /[_~*$?!@/\\;,.=:<>"]/ #" + when /[_~*$?!@\/\\;,.=:<>"]/ #" return when "-" diff --git a/string.c b/string.c index fe8e8e1cef..711f7d81d3 100644 --- a/string.c +++ b/string.c @@ -766,7 +766,7 @@ static VALUE rb_str_succ(orig) VALUE orig; { - VALUE str, str2; + VALUE str; char *sbeg, *s; int c = -1; int n = 0; @@ -1039,7 +1039,7 @@ rb_str_slice_bang(argc, argv, str) VALUE str; { VALUE arg1, arg2; - long pos, len, i; + long pos, len; rb_str_modify(str); if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) { diff --git a/time.c b/time.c index 0c04fc72d8..68d7bde561 100644 --- a/time.c +++ b/time.c @@ -79,12 +79,6 @@ time_s_new(argc, argv, klass) return obj; } -static VALUE -time_initialize() -{ - return Qnil; -} - static VALUE time_new_internal(klass, sec, usec) VALUE klass; diff --git a/util.c b/util.c index 186cfea29d..a8860672c4 100644 --- a/util.c +++ b/util.c @@ -593,28 +593,6 @@ static void mmswap(a, b) register char *a, *b; } } -static void mmswapblock(a, b, size) register char *a, *b; int size; -{ - register int s; - if (mmkind >= 0) { - register char *t = a + (size & (-16)); register int lo = (size & 0x0C); - if (size >= 16) { - do { - s = A[0]; A[0] = B[0]; B[0] = s; - s = A[1]; A[1] = B[1]; B[1] = s; - s = A[2]; A[2] = B[2]; B[2] = s; - s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16; - }while (a < t); - } - if (lo != 0) { s = A[0]; A[0] = B[0]; B[0] = s; - if (lo >= 8) { s = A[1]; A[1] = B[1]; B[1] = s; - if (lo == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} - }else{ - register char *t = a + size; - do {s = *a; *a++ = *b; *b++ = s;} while (a < t); - } -} - static void mmrot3(a, b, c) register char *a, *b, *c; { register int s; diff --git a/variable.c b/variable.c index de034da0dd..e3da3615f0 100644 --- a/variable.c +++ b/variable.c @@ -724,7 +724,6 @@ rb_generic_ivar_table(obj) VALUE obj; { st_table *tbl; - VALUE val; if (!generic_iv_tbl) return 0; if (!st_lookup(generic_iv_tbl, obj, &tbl)) return 0; @@ -1336,7 +1335,6 @@ rb_cvar_set(klass, id, val) ID id; VALUE val; { - VALUE value; VALUE tmp; if (FL_TEST(klass, FL_SINGLETON)) { @@ -1382,7 +1380,6 @@ rb_cvar_defined(klass, id) VALUE klass; ID id; { - VALUE value; VALUE tmp; if (FL_TEST(klass, FL_SINGLETON)) { diff --git a/version.h b/version.h index 91f95200f3..d49ce9b854 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ -#define RUBY_VERSION "1.5.3" -#define RUBY_RELEASE_DATE "2000-05-10" -#define RUBY_VERSION_CODE 153 -#define RUBY_RELEASE_CODE 20000510 +#define RUBY_VERSION "1.5.4" +#define RUBY_RELEASE_DATE "2000-05-12" +#define RUBY_VERSION_CODE 154 +#define RUBY_RELEASE_CODE 20000512