diff --git a/ChangeLog b/ChangeLog index 77a208432a..8a09ecc265 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,53 @@ +Thu Mar 23 02:26:14 2000 Yukihiro Matsumoto + + * io.c (rb_io_fptr_finalize): fptr may be null. + + * io.c (rb_io_s_new): now calls `initialize'. + + * io.c (rb_io_initialize): actual open done in this method. + + * io.c (rb_file_initialize): ditto. + + * eval.c (rb_eval): class variables in singleton class definition + is now handled properly (I hope). + +Wed Mar 22 21:49:36 2000 Minero Aoki + + * st.c (st_delete_safe): skip already deleted entry. + + * hash.c (rb_hash_delete): modify brace miss. + +Wed Mar 22 08:53:58 2000 Yukihiro Matsumoto + + * eval.c (exec_under): do not push cbase if ruby_cbase == under. + + * node.h (NEW_CREF0): preserve cbase nesting. + +Tue Mar 21 12:57:50 2000 Yukihiro Matsumoto + + * object.c (rb_class_s_new): Class::new should call `inherited'. + +Sat Mar 18 12:36:09 2000 Nobuyoshi Nakada + + * eval.c (rb_backtrace, make_backtrace): removed unsed variable + `lev'. + + * eval.c (rb_attr): calls `method_added' at attribute definition. + + * eval.c (rb_mod_modfunc): calls `singleton_method_added' while + `module_function'. + + * eval.c (rb_eval): parameter to `method_added' and + `singleton_method_added' is Symbol. + + * eval.c (Init_eval): caches IDs for `method_added' and + `singleton_method_added'. + +Sat Mar 18 11:25:10 2000 Yukihiro Matsumoto + + * parse.y (rescue): allows `rescue Error in foo'. experimental. + which is better this or preparing alias `exception' for `$!'. + Fri Mar 17 15:02:45 2000 Yukihiro Matsumoto * variable.c (rb_autoload_id): defining new autoload should be @@ -110,7 +160,7 @@ Tue Mar 7 01:44:27 2000 Yukihiro Matsumoto * io.c (set_outfile): ditto. - * re.c (Init_Regexp): new method Regexp#last_match added; it's a + * re.c (Init_Regexp): new method Regexp#last_match added; it's an alternative for $~. * configure.in (DEFAULT_KCODE): KCODE_NONE should be the default. diff --git a/ToDo b/ToDo index 20207c4d2d..3bdc5ab991 100644 --- a/ToDo +++ b/ToDo @@ -5,7 +5,8 @@ Language Spec. - rescue modifier; a rescue b => begin a rescue; b end - %w(a\ b\ c abc) => ["a b c", "abc"] - objectify symbols -- class variable (prefix @@) - still need work for singletons +- class variable (prefix @@) +- rescue RuntimeError in err ?? * operator !! for rescue. ??? * objectify characters * ../... outside condition invokes operator method too. @@ -21,6 +22,8 @@ Language Spec. * I18N (or M17N) script/string/regexp * Fixnum 0 as false ???? * discourage use of symbol variable (e.g. $/, etc.) in manual +* discourage use of Perlish features by giving warnings. +* `exception' method to be alternative for `$!'. ?? Hacking Interpreter @@ -31,7 +34,7 @@ Hacking Interpreter - remove end_proc registered out of require only - all object made freezable * non-blocking open (e.g. for named pipe) for thread -* avoid blocking with gethostbyname/gethostbyaddr +* avoid blocking with gethostbyname/gethostbyaddr (use fork ???) * objectify interpreters * remove rb_eval() recursions * syntax tree -> bytecode ??? @@ -40,7 +43,7 @@ Hacking Interpreter Standard Libraries -- hash[key] = nil may not remove entry; hashes may have nil as the value. +- hash[key] = nil does not remove entry; hashes may have nil as the value. - hash.fetch(key) raises exception if key is not found. - Array#{first,last,at} - Dir.glob(pat){|f|...} @@ -53,13 +56,13 @@ Standard Libraries - debugger for thread programming - SyntaxError, NameError, LoadError and NotImplementError are subclasses of ScriptError..), \G - Struct::new([name,]member,...) - IO#reopen accepts path as well - Kernel#scan -- call initialize for builtin class too (not yet: Regexp, IO, etc) +- call initialize for builtin class too (not yet: Regexp, etc) +- performance tune for String's non-bang methods. * String#scanf(?) * Object#fmt(?) * Integer#{bin,oct,hex,heX} @@ -69,7 +72,6 @@ Standard Libraries * Stream or Port, abstract superclass of IO ? * String#{pred,prev}, String#downto * optional stepsize argument for succ() -* performance tune for String's non-bang methods. * Ruby module -- Ruby::Version, Ruby::Interpreter Extension Libraries diff --git a/eval.c b/eval.c index 1edd45436a..b3a86d1dbe 100644 --- a/eval.c +++ b/eval.c @@ -420,6 +420,8 @@ rb_method_boundp(klass, id, ex) return Qfalse; } +static ID init, eqq, each, aref, aset, match, missing, added, singleton_added; + void rb_attr(klass, id, read, write, ex) VALUE klass; @@ -454,15 +456,16 @@ rb_attr(klass, id, read, write, ex) attriv = rb_intern(buf); if (read) { rb_add_method(klass, id, NEW_IVAR(attriv), noex); + rb_funcall(klass, added, 1, ID2SYM(id)); } sprintf(buf, "%s=", name); id = rb_intern(buf); if (write) { rb_add_method(klass, id, NEW_ATTRSET(attriv), noex); + rb_funcall(klass, added, 1, ID2SYM(id)); } } -static ID init, eqq, each, aref, aset, match, missing; VALUE ruby_errinfo = Qnil; extern NODE *ruby_eval_tree_begin; extern NODE *ruby_eval_tree; @@ -1294,7 +1297,7 @@ superclass(self, node) case NODE_COLON2: rb_raise(rb_eTypeError, "undefined superclass `%s'", rb_id2name(node->nd_mid)); - case NODE_CVAR: + case NODE_CONST: rb_raise(rb_eTypeError, "undefined superclass `%s'", rb_id2name(node->nd_vid)); default: @@ -1310,7 +1313,7 @@ superclass(self, node) return val; } -#define ruby_cbase (((NODE*)ruby_frame->cbase)->nd_clss) +#define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss) static VALUE ev_const_defined(cref, id) @@ -1375,7 +1378,7 @@ ev_const_set(cref, id, val) static VALUE rb_mod_nesting() { - NODE *cbase = (NODE*)ruby_frame->cbase; + NODE *cbase = RNODE(ruby_frame->cbase); VALUE ary = rb_ary_new(); while (cbase && cbase->nd_clss != rb_cObject) { @@ -1388,7 +1391,7 @@ rb_mod_nesting() static VALUE rb_mod_s_constants() { - NODE *cbase = (NODE*)ruby_frame->cbase; + NODE *cbase = RNODE(ruby_frame->cbase); VALUE ary = rb_ary_new(); while (cbase && cbase->nd_clss != rb_cObject) { @@ -1682,8 +1685,8 @@ is_defined(self, node, buf) } break; - case NODE_CVAR: - if (ev_const_defined((NODE*)ruby_frame->cbase, node->nd_vid)) { + case NODE_CONST: + if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid)) { return "constant"; } break; @@ -2494,11 +2497,11 @@ rb_eval(self, node) break; case NODE_CASGN: - if (NIL_P(ruby_class)) { + if (NIL_P(ruby_cbase)) { rb_raise(rb_eTypeError, "no class/module to define constant"); } result = rb_eval(self, node->nd_value); - ev_const_set((NODE*)ruby_frame->cbase, node->nd_vid, result); + ev_const_set(RNODE(ruby_frame->cbase), node->nd_vid, result); break; case NODE_CDECL: @@ -2509,20 +2512,20 @@ rb_eval(self, node) rb_const_set(ruby_class, node->nd_vid, result); break; - case NODE_SHASGN: - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class/module to define shared variable"); + case NODE_CVASGN: + if (NIL_P(ruby_cbase)) { + rb_raise(rb_eTypeError, "no class/module to define class variable"); } result = rb_eval(self, node->nd_value); - rb_shared_variable_set(ruby_cbase, node->nd_vid, result); + rb_cvar_set(ruby_cbase, node->nd_vid, result); break; - case NODE_SHDECL: - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class/module to define shared variable"); + case NODE_CVDECL: + if (NIL_P(ruby_cbase)) { + rb_raise(rb_eTypeError, "no class/module to define class variable"); } result = rb_eval(self, node->nd_value); - rb_shared_variable_declare(ruby_class, node->nd_vid, result); + rb_cvar_declare(ruby_cbase, node->nd_vid, result); break; case NODE_LVAR: @@ -2544,12 +2547,12 @@ rb_eval(self, node) result = rb_ivar_get(self, node->nd_vid); break; - case NODE_CVAR: - result = ev_const_get((NODE*)ruby_frame->cbase, node->nd_vid); + case NODE_CONST: + result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid); break; - case NODE_SHVAR: - result = rb_shared_variable_get(ruby_cbase, node->nd_vid); + case NODE_CVAR: + result = rb_cvar_get(ruby_cbase, node->nd_vid); break; case NODE_BLOCK_ARG: @@ -2760,17 +2763,14 @@ rb_eval(self, node) if (scope_vmode == SCOPE_MODFUNC) { rb_add_method(rb_singleton_class(ruby_class), node->nd_mid, node->nd_defn, NOEX_PUBLIC); - rb_funcall(ruby_class, rb_intern("singleton_method_added"), - 1, INT2FIX(node->nd_mid)); + rb_funcall(ruby_class, singleton_added, 1, ID2SYM(node->nd_mid)); } if (FL_TEST(ruby_class, FL_SINGLETON)) { rb_funcall(rb_iv_get(ruby_class, "__attached__"), - rb_intern("singleton_method_added"), - 1, INT2FIX(node->nd_mid)); + singleton_added, 1, ID2SYM(node->nd_mid)); } else { - rb_funcall(ruby_class, rb_intern("method_added"), - 1, INT2FIX(node->nd_mid)); + rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid)); } result = Qnil; } @@ -2805,8 +2805,7 @@ rb_eval(self, node) rb_clear_cache_by_id(node->nd_mid); rb_add_method(klass, node->nd_mid, node->nd_defn, NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); - rb_funcall(recv, rb_intern("singleton_method_added"), - 1, INT2FIX(node->nd_mid)); + rb_funcall(recv, singleton_added, 1, ID2SYM(node->nd_mid)); result = Qnil; } break; @@ -2824,8 +2823,7 @@ rb_eval(self, node) rb_raise(rb_eTypeError, "no class to make alias"); } rb_alias(ruby_class, node->nd_new, node->nd_old); - rb_funcall(ruby_class, rb_intern("method_added"), - 1, INT2FIX(node->nd_mid)); + rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid)); result = Qnil; break; @@ -3507,16 +3505,16 @@ assign(self, lhs, val, check) break; case NODE_CASGN: - ev_const_set((NODE*)ruby_frame->cbase, lhs->nd_vid, val); + ev_const_set(RNODE(ruby_frame->cbase), lhs->nd_vid, val); break; case NODE_CDECL: rb_const_set(ruby_class, lhs->nd_vid, val); break; - case NODE_SHDECL: - case NODE_SHASGN: - rb_shared_variable_set(ruby_cbase, lhs->nd_vid, val); + case NODE_CVDECL: + case NODE_CVASGN: + rb_cvar_set(ruby_cbase, lhs->nd_vid, val); break; case NODE_MASGN: @@ -4397,10 +4395,9 @@ rb_f_caller(argc, argv) void rb_backtrace() { - int i, lev; + int i; VALUE ary; - lev = INT2FIX(0); ary = backtrace(-1); for (i=0; ilen; i++) { printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr); @@ -4410,9 +4407,6 @@ rb_backtrace() static VALUE make_backtrace() { - VALUE lev; - - lev = INT2FIX(0); return backtrace(-1); } @@ -4598,7 +4592,6 @@ exec_under(func, under, args) VALUE val; /* OK */ int state; int mode; - VALUE cbase = ruby_frame->cbase; PUSH_CLASS(); ruby_class = under; @@ -4607,7 +4600,10 @@ exec_under(func, under, args) ruby_frame->last_class = _frame.prev->last_class; ruby_frame->argc = _frame.prev->argc; ruby_frame->argv = _frame.prev->argv; - ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,cbase); + if (ruby_cbase != under) { + ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase); + } + mode = scope_vmode; SCOPE_SET(SCOPE_PUBLIC); PUSH_TAG(PROT_NONE); @@ -5129,6 +5125,7 @@ rb_mod_modfunc(argc, argv, module) } rb_clear_cache_by_id(id); rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC); + rb_funcall(module, singleton_added, 1, ID2SYM(id)); } return module; } @@ -5398,6 +5395,8 @@ Init_eval() aset = rb_intern("[]="); match = rb_intern("=~"); missing = rb_intern("method_missing"); + added = rb_intern("method_added"); + singleton_added = rb_intern("singleton_method_added"); rb_global_variable((VALUE*)&top_scope); rb_global_variable((VALUE*)&ruby_eval_tree_begin); diff --git a/hash.c b/hash.c index 47681b2117..7d8668b0c3 100644 --- a/hash.c +++ b/hash.c @@ -411,10 +411,11 @@ rb_hash_delete(hash, key) VALUE val; rb_hash_modify(hash); - if (RHASH(hash)->iter_lev > 0 && - st_delete_safe(RHASH(hash)->tbl, &key, &val, Qundef)) { - FL_SET(hash, HASH_DELETED); - return val; + if (RHASH(hash)->iter_lev > 0) { + if (st_delete_safe(RHASH(hash)->tbl, &key, &val, Qundef)) { + FL_SET(hash, HASH_DELETED); + return val; + } } else if (st_delete(RHASH(hash)->tbl, &key, &val)) return val; diff --git a/io.c b/io.c index dcdd1b8476..82b611805a 100644 --- a/io.c +++ b/io.c @@ -942,6 +942,7 @@ void rb_io_fptr_finalize(fptr) OpenFile *fptr; { + if (!fptr) return; rb_io_fptr_close(fptr); if (fptr->path) { free(fptr->path); @@ -1282,41 +1283,41 @@ rb_fdopen(fd, mode) } static VALUE -rb_file_open_internal(klass, fname, mode) - VALUE klass; +rb_file_open_internal(io, fname, mode) + VALUE io; const char *fname, *mode; { OpenFile *fptr; - NEWOBJ(port, struct RFile); - OBJSETUP(port, klass, T_FILE); - MakeOpenFile(port, fptr); + + MakeOpenFile(io, fptr); fptr->mode = rb_io_mode_flags(mode); fptr->f = rb_fopen(fname, mode); fptr->path = strdup(fname); - return (VALUE)port; + return io; } VALUE rb_file_open(fname, mode) const char *fname, *mode; { - return rb_file_open_internal(rb_cFile, fname, mode); + NEWOBJ(io, struct RFile); + OBJSETUP(io, rb_cFile, T_FILE); + return rb_file_open_internal((VALUE)io, fname, mode); } -VALUE -rb_file_sysopen_internal(klass, fname, flags, mode) - VALUE klass; +static VALUE +rb_file_sysopen_internal(io, fname, flags, mode) + VALUE io; char *fname; int flags, mode; { OpenFile *fptr; int fd; char *m; - NEWOBJ(port, struct RFile); - OBJSETUP(port, klass, T_FILE); - MakeOpenFile(port, fptr); + + MakeOpenFile(io, fptr); fd = rb_open(fname, flags, mode); m = rb_io_flags_mode(flags); @@ -1324,7 +1325,7 @@ rb_file_sysopen_internal(klass, fname, flags, mode) fptr->f = rb_fdopen(fd, m); fptr->path = strdup(fname); - return (VALUE)port; + return io; } VALUE @@ -1332,7 +1333,9 @@ rb_file_sysopen(fname, flags, mode) const char *fname; int flags, mode; { - return rb_file_sysopen_internal(rb_cFile, fname, flags, mode); + NEWOBJ(io, struct RFile); + OBJSETUP(io, rb_cFile, T_FILE); + return rb_file_sysopen_internal((VALUE)io, fname, mode); } #if defined (NT) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) @@ -1567,10 +1570,10 @@ rb_io_s_popen(argc, argv, self) } static VALUE -rb_file_s_open(argc, argv, klass) +rb_file_initialize(argc, argv, io) int argc; VALUE *argv; - VALUE klass; + VALUE io; { VALUE fname, vmode, file, perm; char *path, *mode; @@ -1583,7 +1586,7 @@ rb_file_s_open(argc, argv, klass) int flags = NUM2INT(vmode); int fmode = NIL_P(perm) ? 0666 : NUM2INT(perm); - file = rb_file_sysopen_internal(klass, path, flags, fmode); + file = rb_file_sysopen_internal(io, path, flags, fmode); } else { if (!NIL_P(vmode)) { @@ -1592,7 +1595,45 @@ rb_file_s_open(argc, argv, klass) else { mode = "r"; } - file = rb_file_open_internal(klass, RSTRING(fname)->ptr, mode); + file = rb_file_open_internal(io, RSTRING(fname)->ptr, mode); + } + + if (rb_iterator_p()) { + return rb_ensure(rb_yield, file, rb_io_close, file); + } + + return file; +} + +static VALUE +rb_file_s_open(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE fname, vmode, file, perm; + char *path, *mode; + + NEWOBJ(io, struct RFile); + OBJSETUP(io, klass, T_FILE); + rb_scan_args(argc, argv, "12", &fname, &vmode, &perm); + Check_SafeStr(fname); + path = RSTRING(fname)->ptr; + + if (FIXNUM_P(vmode)) { + int flags = NUM2INT(vmode); + int fmode = NIL_P(perm) ? 0666 : NUM2INT(perm); + + file = rb_file_sysopen_internal((VALUE)io, path, flags, fmode); + } + else { + if (!NIL_P(vmode)) { + mode = STR2CSTR(vmode); + } + else { + mode = "r"; + } + file = rb_file_open_internal((VALUE)io, RSTRING(fname)->ptr, mode); } if (rb_iterator_p()) { @@ -2187,15 +2228,41 @@ rb_io_s_new(argc, argv, klass) int argc; VALUE *argv; VALUE klass; +{ + OpenFile *fp; + NEWOBJ(io, struct RFile); + OBJSETUP(io, klass, T_FILE); + + io->fptr = 0; + rb_obj_call_init((VALUE)io, argc, argv); + + return (VALUE)io; +} + +static VALUE +rb_io_initialize(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; { VALUE fnum, mode; + OpenFile *fp; char *m = "r"; + if (RFILE(io)->fptr) { + rb_io_fptr_finalize(RFILE(io)->fptr); + free(RFILE(io)->fptr); + RFILE(io)->fptr = 0; + } if (rb_scan_args(argc, argv, "11", &fnum, &mode) == 2) { Check_SafeStr(mode); m = RSTRING(mode)->ptr; } - return prep_stdio(rb_fdopen(NUM2INT(fnum), m), rb_io_mode_flags(m), klass); + MakeOpenFile(io, fp); + fp->f = rb_fdopen(NUM2INT(fnum), m); + fp->mode = rb_io_mode_flags(m); + + return io; } static int binmode = 0; @@ -3174,6 +3241,7 @@ Init_IO() rb_include_module(rb_cIO, rb_mEnumerable); rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1); + rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1); rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1); rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1); rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1); @@ -3318,8 +3386,8 @@ Init_IO() Init_File(); - rb_define_singleton_method(rb_cFile, "new", rb_file_s_open, -1); rb_define_singleton_method(rb_cFile, "open", rb_file_s_open, -1); + rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1); rb_file_const("RDONLY", INT2FIX(O_RDONLY)); rb_file_const("WRONLY", INT2FIX(O_WRONLY)); diff --git a/lib/date2.rb b/lib/date2.rb index ef8bf832c1..706fec744e 100644 --- a/lib/date2.rb +++ b/lib/date2.rb @@ -1,5 +1,5 @@ -# date2.rb: Written by Tadayoshi Funaba 1998, 1999 -# $Id: date2.rb,v 1.17 1999/09/15 05:34:07 tadf Exp $ +# date2.rb: Written by Tadayoshi Funaba 1998-2000 +# $Id: date2.rb,v 1.18 2000/03/20 16:23:32 tadf Exp $ class Date @@ -110,6 +110,10 @@ class Date def jd_to_mjd(jd) jd - 2400000.5 end def tjd_to_jd(tjd) tjd + 2440000.5 end def jd_to_tjd(jd) jd - 2440000.5 end + def tjd2_to_jd(cycle, tjd) tjd_to_jd(cycle * 10000 + tjd) end + def jd_to_tjd2(jd) clfloor(jd_to_tjd(jd), 10000) end + def ld_to_jd(ld) ld + 2299160 end + def jd_to_ld(jd) jd - 2299160 end def julian_leap? (y) y % 4 == 0 end def gregorian_leap? (y) y % 4 == 0 and y % 100 != 0 or y % 400 == 0 end @@ -213,15 +217,18 @@ class Date def rjd() @rjd end def rmjd() Date.jd_to_mjd(@rjd) end def rtjd() Date.jd_to_tjd(@rjd) end + def rtjd2() Date.jd_to_tjd2(@rjd) end - once :rmjd, :rtjd + once :rmjd, :rtjd, :rtjd2 def jd() Date.rjd_to_jd(@rjd)[0] end def fr1() Date.rjd_to_jd(@rjd)[1] end def mjd() Date.jd_to_mjd(jd) end def tjd() Date.jd_to_tjd(jd) end + def tjd2() Date.jd_to_tjd2(jd) end + def ld() Date.jd_to_ld(jd) end - once :jd, :fr1, :mjd, :tjd + once :jd, :fr1, :mjd, :tjd, :tjd2, :ld def civil() Date.jd_to_civil(jd, @sg) end def ordinal() Date.jd_to_ordinal(jd, @sg) end diff --git a/lib/getopts.rb b/lib/getopts.rb index b513f89f31..490523b878 100644 --- a/lib/getopts.rb +++ b/lib/getopts.rb @@ -1,141 +1,127 @@ # -# getopts.rb - -# $Release Version: $ -# $Revision$ -# $Date$ -# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) +# getopts.rb - +# $Release Version: $ +# $Revision$ +# $Date$ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- # this is obsolete; use getoptlong # +# 2000-03-21 +# modified by Minero Aoki # $RCS_ID=%q$Header$ -def isSingle(lopt) - if lopt.index(":") - if lopt.split(":")[0].length == 1 - return true - end - end - return nil -end -def getOptionName(lopt) - return lopt.split(":")[0] -end +def getopts( single_opts, *options ) + single_opts_exp = (single_opts && !single_opts.empty?) ? + /[#{single_opts}]/ : nil + single_colon_exp = nil + single_colon = nil + opt = arg = val = nil + boolopts = {} + valopts = {} + argv = ARGV + newargv = [] -def getDefaultOption(lopt) - od = lopt.split(":")[1] - if od - return od - end - return nil -end - -def setOption(name, value) - eval("$OPT_" + name + " = " + 'value') -end - -def setDefaultOption(lopt) - d = getDefaultOption(lopt) - if d - setOption(getOptionName(lopt), d) + # + # set default + # + if single_opts then + single_opts.each_byte do |byte| + boolopts[ byte.chr ] = false end end + unless options.empty? then + single_colon = '' -def setNewArgv(newargv) - ARGV.clear - for na in newargv - ARGV << na - end -end - - -def getopts(single_opts, *options) - if options - single_colon = "" - long_opts = [] - sc = 0 - for o in options - setDefaultOption(o) - if isSingle(o) - single_colon[sc, 0] = getOptionName(o) - sc += 1 + options.each do |opt| + m = /\A([^:]+):(.*)\z/.match( opt ) + if m then + valopts[ m[1] ] = m[2].empty? ? 0 : m[2] else - long_opts.push(o) - end + boolopts[ opt ] = false +end + end + valopts.each do |opt, dflt| + if opt.size == 1 then + single_colon << opt +end + end + + if single_colon.empty? then + single_colon = single_colon_exp = nil + else + single_colon_exp = /[#{single_colon}]/ end end - opts = {} - count = 0 - newargv = [] - while ARGV.length != 0 - compare = nil - case ARGV[0] - when /^--?$/ - ARGV.shift - newargv += ARGV + # + # scan + # + c = 0 + arg = argv.shift + while arg do + case arg + when /\A--?\z/ # xinit -- -bpp 24 + newargv.concat argv break - when /^--.*/ - compare = ARGV[0][2, (ARGV[0].length - 2)] - if long_opts != "" - for lo in long_opts - if lo.index(":") && getOptionName(lo) == compare - if ARGV.length <= 1 - return nil - end - setOption(compare, ARGV[1]) - opts[compare] = true - ARGV.shift - count += 1 - break - elsif lo == compare - setOption(compare, true) - opts[compare] = true - count += 1 - break - end - end + + when /\A--(.*)/ + opt = $1 + if valopts.key? opt then # imclean --src +trash + return nil if argv.empty? + valopts[ opt ] = argv.shift + elsif boolopts.key? opt then # ruby --verbose + boolopts[ opt ] = true + else + return nil + end + c += 1 + + when /\A-(.+)/ + arg = $1 + 0.upto( arg.size - 1 ) do |idx| + opt = arg[idx, 1] + if single_opts and single_opts_exp === opt then + boolopts[ opt ] = true # ruby -h + c += 1 + + elsif single_colon and single_colon_exp === opt then + val = arg[ (idx+1)..-1 ] + if val.empty? then # ruby -e 'p $:' + return nil if argv.empty? + valopts[ opt ] = argv.shift + else # cc -ohello ... + valopts[ opt ] = val end - if compare.length <= 1 - return nil + c += 1 + + break + else + return nil + end + end + + else # ruby test.rb + newargv.push arg end - when /^-.*/ - for idx in 1..(ARGV[0].length - 1) - compare = ARGV[0][idx, 1] - if single_opts && compare =~ "[" + single_opts + "]" - setOption(compare, true) - opts[compare] = true - count += 1 - elsif single_colon != "" && compare =~ "[" + single_colon + "]" - if ARGV[0][idx..-1].length > 1 - setOption(compare, ARGV[0][(idx + 1)..-1]) - opts[compare] = true - count += 1 - elsif ARGV.length <= 1 - return nil - else - setOption(compare, ARGV[1]) - opts[compare] = true - ARGV.shift - count += 1 - end - break - end - end - else - compare = ARGV[0] - opts[compare] = true - newargv << ARGV[0] + + arg = argv.shift end - ARGV.shift - if !opts.has_key?(compare) - return nil + # + # set + # + boolopts.each do |opt, val| + eval "$OPT_#{opt} = val" end + valopts.each do |opt, val| + eval "$OPT_#{opt} = #{val == 0 ? 'nil' : 'val'}" end - setNewArgv(newargv) - return count + argv.replace newargv + + c end diff --git a/lib/parsedate.rb b/lib/parsedate.rb index 35fffcfe98..59a8b4f3b4 100644 --- a/lib/parsedate.rb +++ b/lib/parsedate.rb @@ -1,78 +1,590 @@ -module ParseDate +# parsedate2.ry: Written by Tadayoshi Funaba 1999, 2000 +# $Id: parsedate2.ry,v 1.5 2000/03/20 16:23:46 tadf Exp $ +## Generated by rbison version 0.0.5. + +class ParseDatePar + + class ParseError < StandardError ; end + class LexError < StandardError ; end + NULL = nil + + attr :yydebug, true + + DAY = 257 + DIGITS = 258 + MON = 259 + LETTERS = 260 + MERID = 261 + + ## Parser declarations begin + ## Parser declarations end + + YYFINAL = 84 + YYFLAG = -32768 + YYNTBASE = 14 + YYTRANSLATE = [ 0, + 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, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 13, 8, 9, 10, 11, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 12, 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, + 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, 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, 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, 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, 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, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7 + ] + YYPRHS = [ 0, + 0, 1, 3, 6, 8, 12, 14, 20, 26, 32, + 34, 38, 40, 44, 45, 48, 50, 51, 53, 55, + 57, 60, 63, 65, 67, 69, 71, 73, 80, 88, + 94, 98, 104, 108, 115, 116, 119, 122, 123, 125, + 128, 129, 131, 132, 134, 136, 139, 142, 147, 149 + ] + YYRHS = [ -1, + 17, 0, 16, 15, 0, 19, 0, 19, 18, 22, + 0, 28, 0, 28, 18, 19, 18, 22, 0, 19, + 18, 28, 18, 22, 0, 19, 18, 22, 18, 28, + 0, 23, 0, 23, 18, 28, 0, 30, 0, 30, + 18, 32, 0, 0, 17, 18, 0, 3, 0, 0, + 8, 0, 20, 0, 21, 0, 4, 5, 0, 5, + 4, 0, 4, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 4, 9, 4, 9, 4, 31, 0, 6, + 4, 10, 4, 10, 4, 31, 0, 4, 9, 5, + 9, 4, 0, 4, 11, 4, 0, 4, 11, 4, + 11, 4, 0, 4, 7, 34, 0, 4, 12, 4, + 29, 33, 34, 0, 0, 12, 4, 0, 4, 31, + 0, 0, 6, 0, 4, 34, 0, 0, 7, 0, + 0, 35, 0, 6, 0, 6, 6, 0, 36, 4, + 0, 36, 4, 12, 4, 0, 9, 0, 13, 0 + ] + YYRLINE = [ 0, + 14, 14, 14, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 28, 28, 30, 32, 32, 34, 34, + 36, 38, 40, 42, 42, 42, 42, 44, 58, 72, + 86, 91, 105, 109, 116, 116, 118, 141, 141, 143, + 156, 156, 158, 158, 160, 161, 166, 167, 170, 170 + ] + YYTNAME = [ "$","error","$undefined.","DAY","DIGITS", +"MON","LETTERS","MERID","','","'-'","'.'","'/'","':'","'+'","repr","dat","odaycom", +"day","ocom","woy","eu","us","year","wy","iso","jis","vms","sla","time","osec", +"ddd","otee","ttt","omerid","ozone","zone","sign", NULL + ] + YYR1 = [ 0, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 17, 18, 18, 19, 19, + 20, 21, 22, 23, 23, 23, 23, 24, 25, 26, + 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, + 33, 33, 34, 34, 35, 35, 35, 35, 36, 36 + ] + YYR2 = [ 0, + 0, 1, 2, 1, 3, 1, 5, 5, 5, 1, + 3, 1, 3, 0, 2, 1, 0, 1, 1, 1, + 2, 2, 1, 1, 1, 1, 1, 6, 7, 5, + 3, 5, 3, 6, 0, 2, 2, 0, 1, 2, + 0, 1, 0, 1, 1, 2, 2, 4, 1, 1 + ] + YYDEFACT = [ 14, + 16, 0, 17, 38, 0, 0, 3, 4, 19, 20, + 10, 24, 25, 26, 27, 17, 12, 18, 15, 21, + 39, 43, 0, 0, 0, 37, 22, 0, 0, 0, + 0, 0, 45, 49, 50, 33, 44, 0, 0, 0, + 31, 35, 0, 23, 5, 17, 0, 11, 0, 17, + 43, 13, 46, 47, 0, 0, 0, 0, 41, 0, + 0, 0, 0, 40, 0, 38, 30, 32, 36, 42, + 43, 0, 9, 23, 8, 7, 48, 28, 34, 38, + 29, 0, 0, 0 + ] + YYDEFGOTO = [ 82, + 7, 2, 3, 19, 8, 9, 10, 45, 11, 12, + 13, 14, 15, 16, 59, 17, 26, 52, 71, 36, + 37, 38 + ] + YYPACT = [ 10, +-32768, 30, 6, 11, 37, 39,-32768, 23,-32768,-32768, + 23,-32768,-32768,-32768,-32768, 7, 23,-32768,-32768,-32768, +-32768, 19, 25, 40, 41,-32768,-32768, 36, 43, 44, + 35, 45, 46,-32768,-32768,-32768,-32768, 47, 48, 49, + 42, 38, 50, 14, 23, 51, 14,-32768, 55, 51, + 19,-32768,-32768, 52, 57, 58, 59, 61, 60, 56, + 44, 64, 64,-32768, 65, 66,-32768,-32768,-32768,-32768, + 19, 67,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 66, +-32768, 70, 73,-32768 + ] + YYPGOTO = [ -32768, +-32768,-32768,-32768, -8, 24,-32768,-32768, -51,-32768,-32768, +-32768,-32768,-32768, -28,-32768,-32768, -61,-32768,-32768, -47, +-32768,-32768 + ] + YYLAST = 73 + YYTABLE = [ 29, + 46, 48, 30, 64, 78, -2, -6, 31, 32, -1, + 75, 76, 1, 18, 18, 20, 21, 22, 81, 23, + 22, 24, 25, 79, 33, 25, -17, 34, 39, 40, + 18, 35, 73, 4, 5, 6, 61, 62, 49, 5, + 27, 63, 28, 41, 42, 43, 44, 47, 51, 58, + 54, 53, 57, 60, 50, 0, 55, 56, 18, 20, + 66, 67, 68, 65, 69, 72, 70, 74, 77, 83, + 80, 21, 84 + ] + YYCHECK = [ 8, + 29, 30, 11, 51, 66, 0, 0, 16, 17, 0, + 62, 63, 3, 8, 8, 5, 6, 7, 80, 9, + 7, 11, 12, 71, 6, 12, 4, 9, 4, 5, + 8, 13, 61, 4, 5, 6, 45, 46, 4, 5, + 4, 50, 4, 4, 4, 10, 4, 4, 4, 12, + 4, 6, 11, 4, 31, -1, 9, 9, 8, 5, + 4, 4, 4, 12, 4, 10, 7, 4, 4, 0, + 4, 6, 0 + ] + YYEMPTY = -2 + YYEOF = 0 + YYTERROR = 1 + + def initialize + @yydebug = false + end + + def yyparse(lexer) + yyerrstatus = 0 + yychar = YYEMPTY + yystate = 0 + yyss = [] + yyvs = ["nil"] + yyval = 0 + jump = :YYNEWSTATE + + while true + + case jump + + when :YYNEWSTATE + if @yydebug + printf($stderr, "Entering state %d\n", yystate) + end + yyss.push(yystate) + jump = :YYBACKUP + next + + when :YYBACKUP + yyn = YYPACT[yystate] + if yyn == YYFLAG + jump = :YYDEFAULT + next + end + + ## get a lookahead token if we don't already have one + if yychar == YYEMPTY + if @yydebug + printf($stderr, "Reading a token: ") + end + begin + yychar, yylval = lexer.yylex + rescue LexError + raise ParseError, "lex error" + end + end + + ## if lookahead <= 0, end of input + if yychar <= 0 + yychar1 = 0 + yychar = YYEOF + if @yydebug + printf($stderr, "Now at end of input.\n") + end + else + yychar1 = yychar < 0 || yychar > 261 ? 37 : YYTRANSLATE[yychar] + if @yydebug + printf($stderr, "Next token is %d (%s,%s)\n", yychar, + YYTNAME[yychar1], yylval) + end + end + + ## see if we know what to do with this token in this state + yyn += yychar1 + if yyn < 0 || yyn > YYLAST || YYCHECK[yyn] != yychar1 + jump = :YYDEFAULT + next + end + + ## yyn is what to do for this token type in this state + ## negative -> reduce, - yyn is the rule number + ## positive -> shift, yyn is the new state + ## New state is final state, don't bother to shift, just + ## return success + ## 0, or most negative number -> error + yyn = YYTABLE[yyn] + if yyn < 0 + if yyn == YYFLAG + jump = :YYERRLAB + next + end + yyn = - yyn + jump = :YYREDUCE + next + elsif yyn == 0 + jump = :YYERRLAB + next + end + + if yyn == YYFINAL + return ## accept + end + + ## shift the lookahead token + if @yydebug + printf($stderr, "Shifting token %d (%s), ", yychar, + YYTNAME[yychar1]) + end + + ## discard the token being shifted unless it is eof + if yychar != YYEOF + yychar = YYEMPTY + end + yyvs.push(yylval) + + ## count tokens shifted since error; after, three turn off + ## error status + yyerrstatus -= 1 if yyerrstatus > 0 + + yystate = yyn + jump = :YYNEWSTATE + next + + when :YYDEFAULT + yyn = YYDEFACT[yystate] + if yyn == 0 + jump = :YYERRLAB + next + else + jump = :YYREDUCE + next + end + + ## do a reduction. yyn is the number of the rule to reduce with + when :YYREDUCE + yylen = YYR2[yyn] + if yylen > 0 + yyval = yyvs[yyvs.size - yylen] + end + + if @yydebug + printf($stderr, "Reducing via rule %d (line %d), ", yyn, + YYRLINE[yyn]) + i = YYPRHS[yyn] + while YYRHS[i] > 0 + printf($stderr, "%s ", YYTNAME[YYRHS[i]]) + i += 1 + end + printf($stderr, " -> %s\n", YYTNAME[YYR1[yyn]]) + end + + case yyn + when 16 + store(:wday, yyvs[-1].to_i) + when 21 + store(:mday, yyvs[-2].to_i); store(:mon, yyvs[-1]) + when 22 + store(:mon, yyvs[-2]); store(:mday, yyvs[-1].to_i) + when 23 + store(:year, yyvs[-1].to_i) + when 28 + + if yyvs[-1 + -1].size >= 4 + store(:mday, yyvs[-1 + -5].to_i) + store(:mon, yyvs[-1 + -3].to_i) + store(:year, yyvs[-1 + -1].to_i) + else + store(:year, yyvs[-1 + -5].to_i) + store(:mon, yyvs[-1 + -3].to_i) + store(:mday, yyvs[-1 + -1].to_i) + end + + when 29 + + e = { 'M'=>1867, + 'T'=>1911, + 'S'=>1925, + 'H'=>1988 + }[yyvs[-1 + -6]] + raise ParseError, 'YYERROR' unless e + store(:year, yyvs[-1 + -5].to_i + e) + store(:mon, yyvs[-1 + -3].to_i) + store(:mday, yyvs[-1 + -1].to_i) + + when 30 + + if yyvs[-1 + -4].size >= 4 + store(:year, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2]) + store(:mday, yyvs[-1 + 0].to_i) + else + store(:mday, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2]) + store(:year, yyvs[-1 + 0].to_i) + end + + when 31 + + store(:mon, yyvs[-1 + -2].to_i) + store(:mday, yyvs[-1 + 0].to_i) + + when 32 + + if yyvs[-1 + -4].size >= 4 + store(:year, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2].to_i) + store(:mday, yyvs[-1 + 0].to_i) + else + store(:mon, yyvs[-1 + -4].to_i) + store(:mday, yyvs[-1 + -2].to_i) + store(:year, yyvs[-1 + 0].to_i) + end + + when 33 + + store(:hour, yyvs[-1 + -2].to_i + yyvs[-1 + -1]) + + when 34 + + store(:hour, yyvs[-1 + -5].to_i + yyvs[-1 + -1]) + store(:min, yyvs[-1 + -3].to_i) + + when 36 + store(:sec, yyvs[-1].to_i) + when 37 + + case yyvs[-1 + -1].size + when 4 + store(:mon, yyvs[-1 + -1][ 0, 2].to_i) + store(:mday, yyvs[-1 + -1][ 2, 2].to_i) + when 6 + store(:year, yyvs[-1 + -1][ 0, 2].to_i) + store(:mon, yyvs[-1 + -1][ 2, 2].to_i) + store(:mday, yyvs[-1 + -1][ 4, 2].to_i) + when 8, 10, 12, 14 + store(:year, yyvs[-1 + -1][ 0, 4].to_i) + store(:mon, yyvs[-1 + -1][ 4, 2].to_i) + store(:mday, yyvs[-1 + -1][ 6, 2].to_i) + store(:hour, yyvs[-1 + -1][ 8, 2].to_i) if yyvs[-1 + -1].size >= 10 + store(:min, yyvs[-1 + -1][10, 2].to_i) if yyvs[-1 + -1].size >= 12 + store(:sec, yyvs[-1 + -1][12, 2].to_i) if yyvs[-1 + -1].size >= 14 + else + raise ParseError, 'YYERROR' + end + + when 39 + raise ParseError, 'YYERROR' unless yyvs[-1] == 'T' + when 40 + + case yyvs[-1 + -1].size + when 2, 4, 6 + store(:hour, yyvs[-1 + -1][ 0, 2].to_i) + store(:min, yyvs[-1 + -1][ 2, 2].to_i) if yyvs[-1 + -1].size >= 4 + store(:sec, yyvs[-1 + -1][ 4, 2].to_i) if yyvs[-1 + -1].size >= 6 + else + raise ParseError, 'YYERROR' + end + + when 41 + yyval = 0 + when 45 + store(:zone, yyvs[-1]) + when 46 + + raise ParseError, 'YYERROR' unless yyvs[-1 + 0] == 'DST' + store(:zone, yyvs[-1 + -1] + ' ' + yyvs[-1 + 0]) + + when 47 + store(:zone, yyvs[-2] + yyvs[-1]) + when 48 + store(:zone, yyvs[-4] + yyvs[-3] + yyvs[-2] + yyvs[-1]) + when -65536 ## never used, placeholder for ruby + end + + if yylen > 0 + yyss[(yyss.size - yylen) .. (yyss.size - 1)] = [] + yyvs[(yyvs.size - yylen) .. (yyvs.size - 1)] = [] + end + + yyvs.push(yyval) + + if @yydebug + printf($stderr, "State stack now: %s\n", yyss.join(' ')) + printf($stderr, "Value stack now: %s\n", yyvs.join(' ')) + end + + ## "Shift" the result of the reduction. + yyn = YYR1[yyn] + yystate = YYPGOTO[yyn - YYNTBASE] + yyss[-1] + if yystate >=0 && yystate <= YYLAST && + YYCHECK[yystate] == yyss[-1] + yystate = YYTABLE[yystate] + else + yystate = YYDEFGOTO[yyn - YYNTBASE] + end + jump = :YYNEWSTATE + next + + when :YYERRLAB + if yyerrstatus == 0 && @yydebug + printf($stderr, "Parse error!\n") + end + jump = :YYERRLAB1 + next + + when :YYERRLAB1 + if yyerrstatus == 3 + if yychar == YYEOF + raise ParseError, "parse error" + end + if @yydebug + printf($stderr, "Discarding token %d (%s).\n", yychar, + YYTNAME[yychar1]) + end + yychar = YYEMPTY + end + + yyerrstatus = 3 + jump = :YYERRHANDLE + next + + when :YYERRPOP + if yyvs.empty? + raise ParseError, "parse error" + end + ## don't pop if the state on top of the stack can handle + ## the error token + yystate = yyss[-1] + if YYCHECK[YYPACT[yystate] + YYTERROR] != YYTERROR + yyvs.pop + yyss.pop + if @yydebug + printf($stderr, "Error: state stack now: %s\n", + yyss.join(' ')) + printf($stderr, "Error: Value stack now: %s\n", + yyvs.join(' ')) + end + end + jump = :YYERRHANDLE + next + + when :YYERRHANDLE + yyn = YYPACT[yystate] + if yyn == YYFLAG + jump = :YYERRPOP + next + end + + yyn += YYTERROR + if yyn < 0 || yyn > YYLAST || YYCHECK[yyn] != YYTERROR + jump = :YYERRPOP + next + end + + yyn = YYTABLE[yyn] + if yyn < 0 + if yyn == YYFLAG + jump = :YYERRPOP + next + end + yyn = -yyn + jump = :YYREDUCE + next + elsif yyn == 0 + jump = :YYERRPOP + next + end + + if yyn == YYFINAL + return ## accept + end + + if @yydebug + printf($stderr, "Shifting error token, ") + end + + yyvs.push(yylval) + yystate = yyn + jump = :YYNEWSTATE + next + + end ## case + + end ## while true + + end ## yyparse + +end ## class + +## Additional user code +class ParseDateLex MONTHS = { 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, - 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 } - MONTHPAT = MONTHS.keys.join('|') + 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 + } + MONTHPAT = MONTHS.keys.sort.reverse.join('|') DAYS = { 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, - 'thu' => 4, 'fri' => 5, 'sat' => 6 } - DAYPAT = DAYS.keys.join('|') - - def parsedate(date, guess=false) - # part of ISO 8601 - # yyyy-mm-dd | yyyy-mm | yyyy - # date hh:mm:ss | date Thh:mm:ss - if date =~ /^(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)? *T?(?:(\d\d):?(\d\d):?(\d\d)?)?$/ - return $1.to_i, - if $2 then $2.to_i else 1 end, - if $3 then $3.to_i else 1 end, - if $4 then $4.to_i end, - if $5 then $5.to_i end, - if $6 then $6.to_i end, - nil, - nil + 'thu' => 4, 'fri' => 5, 'sat' => 6 + } + DAYPAT = DAYS.keys.sort.reverse.join('|') + def initialize(str) @str = str end + def reset(str) @str = str end + def yylex + @str = @str.sub(/\A\s+/, '') + return [-1, nil] if @str.size == 0 + if /\A(#{DAYPAT})[a-z]*\.?/i =~ @str + @str = $' + return [ParseDatePar::DAY, DAYS[$1[0, 3].downcase]] end - date = date.dup - if date.sub!(/(#{DAYPAT})[a-z]*,?/i, ' ') - wday = DAYS[$1.downcase] + if /\A(\d+)(?:(?:th|st|nd|rd)\b)?/ =~ @str + @str = $' + return [ParseDatePar::DIGITS, $1] end - if date.sub!(/(\d+):(\d+)(?::(\d+))?(?:\s*(am|pm))?(?:\s+([a-z]{1,4}(?:\s+[a-z]{1,4}|[-+]\d{4})?|[-+]\d{4}))?/i, ' ') - hour = $1.to_i - min = $2.to_i - if $3 - sec = $3.to_i - end - if $4 == 'pm' - hour += 12 - end - if $5 - zone = $5 - end + if /\A(#{MONTHPAT})[a-z]*\.?/i =~ @str + @str = $' + return [ParseDatePar::MON, MONTHS[$1[0, 3].downcase]] end - if date.sub!(/(\d+)\S*\s+(#{MONTHPAT})\S*(?:\s+(\d+))?/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - if $3 - year = $3.to_i - end - elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*,?(?:\s+(\d+))?/i, ' ') - mon = MONTHS[$1.downcase] - mday = $2.to_i - if $3 - year = $3.to_i - end - elsif date.sub!(/(\d+)\/(\d+)(?:\/(\d+))/, ' ') - mon = $1.to_i - mday = $2.to_i - if $3 - year = $3.to_i - end - elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - year = $3.to_i - elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - year = $3.to_i + if /\A([ap]\.?m\.?\b)/i =~ @str + @str = $' + return [ParseDatePar::MERID, + if $1[0, 1].downcase == 'a' then 0 else 12 end] end - if date.sub!(/\d{4}/i, ' ') - year = $&.to_i - elsif date.sub!(/\d\d/i, ' ') - year = $&.to_i + if /\A([a-z]+)/i =~ @str + @str = $' + return [ParseDatePar::LETTERS, $1] end - if guess and year + if /\A(.)/ =~ @str + @str = $' + return [$1[0], $1] + end + end +end +class ParseDatePar + def clear() @values = {} end + def store(key, val) @values[key] = val end + def values(cyear) + year = @values[:year] + if cyear and year if year < 100 if year >= 69 year += 1900 @@ -81,13 +593,18 @@ module ParseDate end end end - return year, mon, mday, hour, min, sec, zone, wday + @values[:year] = year + @values.indexes(:year, :mon, :mday, + :hour, :min, :sec, :zone, :wday) + end +end +module ParseDate + def parsedate(date, cyear=false) + lex = ParseDateLex.new(date) + par = ParseDatePar.new + par.clear + begin par.yyparse(lex); rescue; end + par.values(cyear) end - module_function :parsedate end - -if __FILE__ == $0 - p Time.now.asctime - p ParseDate.parsedate(Time.now.asctime) -end diff --git a/node.h b/node.h index a7ee1a0d14..04b2b87888 100644 --- a/node.h +++ b/node.h @@ -50,8 +50,8 @@ enum node_type { NODE_IASGN, NODE_CASGN, NODE_CDECL, - NODE_SHASGN, - NODE_SHDECL, + NODE_CVASGN, + NODE_CVDECL, NODE_OP_ASGN1, NODE_OP_ASGN2, NODE_OP_ASGN_AND, @@ -70,8 +70,8 @@ enum node_type { NODE_DVAR, NODE_GVAR, NODE_IVAR, + NODE_CONST, NODE_CVAR, - NODE_SHVAR, NODE_NTH_REF, NODE_BACK_REF, NODE_MATCH, @@ -267,8 +267,8 @@ typedef struct RNode { #define NEW_IASGN(v,val) rb_node_newnode(NODE_IASGN,v,val,0) #define NEW_CASGN(v,val) rb_node_newnode(NODE_CASGN,v,val,0) #define NEW_CDECL(v,val) rb_node_newnode(NODE_CDECL,v,val,0) -#define NEW_SHASGN(v,val) rb_node_newnode(NODE_SHASGN,v,val,0) -#define NEW_SHDECL(v,val) rb_node_newnode(NODE_SHDECL,v,val,0) +#define NEW_CVASGN(v,val) rb_node_newnode(NODE_CVASGN,v,val,0) +#define NEW_CVDECL(v,val) rb_node_newnode(NODE_CVDECL,v,val,0) #define NEW_OP_ASGN1(p,id,a) rb_node_newnode(NODE_OP_ASGN1,p,id,a) #define NEW_OP_ASGN2(r,i,o,val) rb_node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN22(i,o)) #define NEW_OP_ASGN22(i,o) rb_node_newnode(NODE_OP_ASGN2,i,o,rb_id_attrset(i)) @@ -278,8 +278,8 @@ typedef struct RNode { #define NEW_LVAR(v) rb_node_newnode(NODE_LVAR,v,0,local_cnt(v)) #define NEW_DVAR(v) rb_node_newnode(NODE_DVAR,v,0,0); #define NEW_IVAR(v) rb_node_newnode(NODE_IVAR,v,0,0) +#define NEW_CONST(v) rb_node_newnode(NODE_CONST,v,0,0) #define NEW_CVAR(v) rb_node_newnode(NODE_CVAR,v,0,0) -#define NEW_SHVAR(v) rb_node_newnode(NODE_SHVAR,v,0,0) #define NEW_NTH_REF(n) rb_node_newnode(NODE_NTH_REF,0,n,local_cnt('~')) #define NEW_BACK_REF(n) rb_node_newnode(NODE_BACK_REF,0,n,local_cnt('~')) #define NEW_MATCH(c) rb_node_newnode(NODE_MATCH,c,0,0) @@ -310,7 +310,7 @@ typedef struct RNode { #define NEW_MODULE(n,b) rb_node_newnode(NODE_MODULE,n,NEW_CBODY(b),0) #define NEW_COLON2(c,i) rb_node_newnode(NODE_COLON2,c,i,0) #define NEW_COLON3(i) rb_node_newnode(NODE_COLON3,0,i,0) -#define NEW_CREF0() (cur_cref=rb_node_newnode(NODE_CREF,RNODE(ruby_frame->cbase)->nd_clss,0,0)) +#define NEW_CREF0() (cur_cref=RNODE(ruby_frame->cbase)) #define NEW_CREF() (cur_cref=rb_node_newnode(NODE_CREF,0,0,cur_cref)) #define NEW_CBODY(b) (cur_cref->nd_body=NEW_SCOPE(b),cur_cref) #define NEW_DOT2(b,e) rb_node_newnode(NODE_DOT2,b,e,0) diff --git a/object.c b/object.c index 2b9d47f899..1f11e96b7f 100644 --- a/object.c +++ b/object.c @@ -649,6 +649,7 @@ rb_class_s_new(argc, argv) /* make metaclass */ RBASIC(klass)->klass = rb_singleton_class_new(RBASIC(super)->klass); rb_singleton_class_attached(RBASIC(klass)->klass, klass); + rb_funcall(super, rb_intern("inherited"), 1, klass); return klass; } diff --git a/parse.y b/parse.y index 791345dac2..63cb9f0f21 100644 --- a/parse.y +++ b/parse.y @@ -27,7 +27,7 @@ #define ID_GLOBAL 0x03 #define ID_ATTRSET 0x04 #define ID_CONST 0x05 -#define ID_SHARED 0x06 +#define ID_CLASS 0x06 #define is_notop_id(id) ((id)>LAST_TOKEN) #define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) @@ -35,7 +35,7 @@ #define is_instance_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) #define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) #define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) -#define is_shared_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_SHARED) +#define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS) NODE *ruby_eval_tree_begin = 0; NODE *ruby_eval_tree = 0; @@ -166,17 +166,17 @@ static void top_local_setup(); k__LINE__ k__FILE__ -%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tSHVAR +%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR %token tINTEGER tFLOAT tSTRING tXSTRING tREGEXP %token tDSTRING tDXSTRING tDREGEXP tNTH_REF tBACK_REF %type singleton string %type literal numeric %type compstmt stmts stmt expr arg primary command_call method_call -%type if_tail opt_else case_body cases rescue ensure +%type if_tail opt_else case_body cases rescue exc_list exc_var ensure %type opt_call_args call_args ret_args args when_args %type aref_args opt_block_arg block_arg stmt_rhs -%type mrhs opt_list superclass generic_call block_call var_ref +%type mrhs superclass generic_call block_call var_ref %type f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg %type array assoc_list assocs assoc undef_list backref %type block_var opt_block_var brace_block do_block lhs none @@ -918,9 +918,6 @@ opt_block_arg : ',' block_arg } | none -opt_list : args - | none - args : arg { value_expr($1); @@ -1428,12 +1425,25 @@ when_args : args cases : opt_else | case_body -rescue : kRESCUE opt_list do +exc_list : args + | none + +exc_var : kIN lhs + { + $$ = $2; + } + | none + +rescue : kRESCUE exc_list exc_var do compstmt rescue { - $$ = NEW_RESBODY($2, $4, $5); - fixpos($$, $2?$2:$4); + if ($3 && $5) { + $3 = node_assign($3, NEW_GVAR(rb_intern("$!"))); + $5 = block_append($3, $5); + } + $$ = NEW_RESBODY($2, $5, $6); + fixpos($$, $2?$2:$5); } | none @@ -1496,7 +1506,7 @@ variable : tIDENTIFIER | tIVAR | tGVAR | tCONSTANT - | tSHVAR + | tCVAR | kNIL {$$ = kNIL;} | kSELF {$$ = kSELF;} | kTRUE {$$ = kTRUE;} @@ -3386,7 +3396,7 @@ yylex() case '@': lex_state = EXPR_END; if (tok()[1] == '@') - result = tSHVAR; + result = tCVAR; else result = tIVAR; break; @@ -3838,10 +3848,10 @@ gettable(id) return NEW_IVAR(id); } else if (is_const_id(id)) { - return NEW_CVAR(id); + return NEW_CONST(id); } - else if (is_shared_id(id)) { - return NEW_SHVAR(id); + else if (is_class_id(id)) { + return NEW_CVAR(id); } rb_bug("invalid id for gettable"); return 0; @@ -3899,12 +3909,12 @@ assignable(id, val) yyerror("dynamic constant assignment"); lhs = NEW_CDECL(id, val); } - else if (is_shared_id(id)) { + else if (is_class_id(id)) { if (cur_mid || in_single) { - lhs = NEW_SHASGN(id, val); + lhs = NEW_CVASGN(id, val); } else { - lhs = NEW_SHDECL(id, val); + lhs = NEW_CVDECL(id, val); } } else { @@ -3994,8 +4004,8 @@ node_assign(lhs, rhs) case NODE_MASGN: case NODE_CASGN: case NODE_CDECL: - case NODE_SHASGN: - case NODE_SHDECL: + case NODE_CVASGN: + case NODE_CVDECL: lhs->nd_value = rhs; break; @@ -4099,11 +4109,12 @@ void_expr(node) case NODE_DVAR: case NODE_GVAR: case NODE_IVAR: + case NODE_CVAR: case NODE_NTH_REF: case NODE_BACK_REF: useless = "a variable"; break; - case NODE_CVAR: + case NODE_CONST: case NODE_CREF: useless = "a constant"; break; @@ -4607,7 +4618,7 @@ rb_intern(name) break; case '@': if (name[1] == '@') - id |= ID_SHARED; + id |= ID_CLASS; else id |= ID_INSTANCE; break; @@ -4701,10 +4712,10 @@ rb_is_const_id(id) } int -rb_is_shared_id(id) +rb_is_class_id(id) ID id; { - if (is_shared_id(id)) return Qtrue; + if (is_class_id(id)) return Qtrue; return Qfalse; } diff --git a/rubyio.h b/rubyio.h index b0d9cda3ec..a9ab174526 100644 --- a/rubyio.h +++ b/rubyio.h @@ -35,6 +35,7 @@ typedef struct OpenFile { #define GetOpenFile(obj,fp) rb_io_check_closed((fp) = RFILE(obj)->fptr) #define MakeOpenFile(obj, fp) do {\ + fp = 0;\ fp = RFILE(obj)->fptr = ALLOC(OpenFile);\ fp->f = fp->f2 = NULL;\ fp->mode = 0;\ diff --git a/sample/eval.rb b/sample/eval.rb index b9a54df34c..8b582b0fdc 100644 --- a/sample/eval.rb +++ b/sample/eval.rb @@ -12,7 +12,7 @@ while TRUE print "ruby| " next end - if l =~ /^\s*(class|module|def|if|case|while|for|begin)\b[^_]/ + if l =~ /^\s*(class|module|def|if|unless|case|while|until|for|begin)\b[^_]/ indent += 1 end if l =~ /^\s*end\b[^_]/ diff --git a/st.c b/st.c index ede02b2169..2ce868d64c 100644 --- a/st.c +++ b/st.c @@ -435,7 +435,7 @@ st_delete_safe(table, key, value, never) } for(; ptr != 0; ptr = ptr->next) { - if (EQUAL(table, ptr->key, *key)) { + if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) { table->num_entries--; *key = ptr->key; if (value != 0) *value = ptr->record; diff --git a/string.c b/string.c index 7759b5e004..7184080b1b 100644 --- a/string.c +++ b/string.c @@ -886,12 +886,16 @@ rb_str_replace(str, beg, len, val) long beg; long len; { + if (RSTRING(str)->len < beg + len) { + len = RSTRING(str)->len - beg; + } + if (len < RSTRING(val)->len) { /* expand string */ REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+RSTRING(val)->len-len+1); } - if (len != RSTRING(val)->len) { + if (RSTRING(val)->len != len) { memmove(RSTRING(str)->ptr + beg + RSTRING(val)->len, RSTRING(str)->ptr + beg + len, RSTRING(str)->len - (beg + len)); @@ -899,7 +903,9 @@ rb_str_replace(str, beg, len, val) if (RSTRING(str)->len < beg && len < 0) { MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, -len); } - memmove(RSTRING(str)->ptr+beg, RSTRING(val)->ptr, RSTRING(val)->len); + if (RSTRING(val)->len > 0) { + memmove(RSTRING(str)->ptr+beg, RSTRING(val)->ptr, RSTRING(val)->len); + } RSTRING(str)->len += RSTRING(val)->len - len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } @@ -1017,6 +1023,9 @@ rb_str_slice_bang(argc, argv, str) if (pos < 0) { pos = RSTRING(str)->len + pos; } + if (pos < 0 || RSTRING(str)->len <= pos) { + rb_raise(rb_eIndexError, "index %d out of string", pos); + } arg2 = rb_str_substr(str, pos, len); rb_str_replace(str, pos, len, rb_str_new(0,0)); return arg2; diff --git a/variable.c b/variable.c index 691a0159e3..d276fc1e3e 100644 --- a/variable.c +++ b/variable.c @@ -1315,16 +1315,19 @@ rb_define_global_const(name, val) } void -rb_shared_variable_declare(klass, id, val) +rb_cvar_declare(klass, id, val) VALUE klass; ID id; VALUE val; { - rb_mod_av_set(klass, id, val, "shared variable"); + if (FL_TEST(klass, FL_SINGLETON)) { + klass = rb_iv_get(klass, "__attached__"); + } + rb_mod_av_set(klass, id, val, "class variable"); } void -rb_shared_variable_set(klass, id, val) +rb_cvar_set(klass, id, val) VALUE klass; ID id; VALUE val; @@ -1332,6 +1335,9 @@ rb_shared_variable_set(klass, id, val) VALUE value; VALUE tmp; + if (FL_TEST(klass, FL_SINGLETON)) { + klass = rb_iv_get(klass, "__attached__"); + } tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { @@ -1341,17 +1347,20 @@ rb_shared_variable_set(klass, id, val) tmp = RCLASS(tmp)->super; } - rb_raise(rb_eNameError,"uninitialized shared variable %s",rb_id2name(id)); + rb_raise(rb_eNameError,"uninitialized class variable %s",rb_id2name(id)); } VALUE -rb_shared_variable_get(klass, id) +rb_cvar_get(klass, id) VALUE klass; ID id; { VALUE value; VALUE tmp; + if (FL_TEST(klass, FL_SINGLETON)) { + klass = rb_iv_get(klass, "__attached__"); + } tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { @@ -1360,18 +1369,21 @@ rb_shared_variable_get(klass, id) tmp = RCLASS(tmp)->super; } - rb_raise(rb_eNameError,"uninitialized shared variable %s",rb_id2name(id)); + rb_raise(rb_eNameError,"uninitialized class variable %s",rb_id2name(id)); return Qnil; /* not reached */ } int -rb_shared_variable_defined(klass, id) +rb_cvar_defined(klass, id) VALUE klass; ID id; { VALUE value; VALUE tmp; + if (FL_TEST(klass, FL_SINGLETON)) { + klass = rb_iv_get(klass, "__attached__"); + } tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { @@ -1384,17 +1396,34 @@ rb_shared_variable_defined(klass, id) } void -rb_define_shared_variable(klass, name, val) +rb_cv_set(klass, name, val) + VALUE klass; + const char *name; + VALUE val; +{ + rb_cvar_set(klass, rb_intern(name), val); +} + +VALUE +rb_cv_get(klass, name) + VALUE klass; + const char *name; +{ + return rb_cvar_get(klass, rb_intern(name)); +} + +void +rb_define_class_variable(klass, name, val) VALUE klass; const char *name; VALUE val; { ID id = rb_intern(name); - if (!rb_is_shared_id(id)) { - rb_raise(rb_eNameError, "wrong shared variable name %s", name); + if (!rb_is_class_id(id)) { + rb_raise(rb_eNameError, "wrong class variable name %s", name); } - rb_shared_variable_declare(klass, id, val); + rb_cvar_declare(klass, id, val); } VALUE diff --git a/version.h b/version.h index 8cdd0997be..211d7814f0 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ #define RUBY_VERSION "1.5.3" -#define RUBY_RELEASE_DATE "2000-03-17" +#define RUBY_RELEASE_DATE "2000-03-23" #define RUBY_VERSION_CODE 153 -#define RUBY_RELEASE_CODE 20000317 +#define RUBY_RELEASE_CODE 20000323