diff options
| -rw-r--r-- | include/mruby.h | 14 | ||||
| -rw-r--r-- | include/mruby/class.h | 4 | ||||
| -rw-r--r-- | include/mruby/data.h | 1 | ||||
| -rw-r--r-- | include/mruby/hash.h | 11 | ||||
| -rw-r--r-- | include/mruby/object.h | 4 | ||||
| -rw-r--r-- | include/mruby/range.h | 2 | ||||
| -rw-r--r-- | include/mruby/string.h | 5 | ||||
| -rw-r--r-- | mrblib/Makefile | 7 | ||||
| -rw-r--r-- | mrblib/enum.rb | 167 | ||||
| -rw-r--r-- | mrblib/error.rb | 11 | ||||
| -rw-r--r-- | mrblib/string.rb | 64 | ||||
| -rw-r--r-- | src/Makefile | 13 | ||||
| -rw-r--r-- | src/class.c | 38 | ||||
| -rw-r--r-- | src/codegen.c | 1 | ||||
| -rw-r--r-- | src/error.c | 1 | ||||
| -rw-r--r-- | src/etc.c | 19 | ||||
| -rw-r--r-- | src/eval_intern.h | 223 | ||||
| -rw-r--r-- | src/gc.c | 7 | ||||
| -rw-r--r-- | src/gc.h | 12 | ||||
| -rw-r--r-- | src/hash.c | 116 | ||||
| -rw-r--r-- | src/init.c | 1 | ||||
| -rw-r--r-- | src/kernel.c | 13 | ||||
| -rw-r--r-- | src/object.c | 2 | ||||
| -rw-r--r-- | src/proc.c | 2 | ||||
| -rw-r--r-- | src/range.c | 17 | ||||
| -rw-r--r-- | src/time.c | 600 | ||||
| -rw-r--r-- | src/vm.c | 34 | ||||
| -rw-r--r-- | test/test_time.rb | 50 | ||||
| -rw-r--r-- | tools/mrbc/Makefile | 4 | ||||
| -rw-r--r-- | tools/mruby/Makefile | 4 |
30 files changed, 1028 insertions, 419 deletions
diff --git a/include/mruby.h b/include/mruby.h index 6efa54858..6ed8e4878 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -68,7 +68,7 @@ typedef struct mrb_value { mrb_int i; mrb_sym sym; } value; - enum mrb_vtype tt; + enum mrb_vtype tt:8; } mrb_value; #define mrb_type(o) (o).tt @@ -342,6 +342,7 @@ void *mrb_realloc(mrb_state*, void*, size_t); void *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*); void *mrb_free(mrb_state*, void*); +mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); /* mrb_str_new */ mrb_value mrb_str_new_cstr(mrb_state*, const char*); mrb_state* mrb_open(void); @@ -371,17 +372,6 @@ void mrb_gc_mark(mrb_state*,struct RBasic*); #define mrb_gc_mark_value(mrb,val) do {\ if ((val).tt >= MRB_TT_OBJECT) mrb_gc_mark((mrb), mrb_object(val));\ } while (0); -void mrb_gc_mark_gv(mrb_state*); -void mrb_gc_free_gv(mrb_state*); -void mrb_gc_mark_iv(mrb_state*, struct RObject*); -size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); -void mrb_gc_free_iv(mrb_state*, struct RObject*); -void mrb_gc_mark_mt(mrb_state*, struct RClass*); -size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); -void mrb_gc_free_mt(mrb_state*, struct RClass*); -void mrb_gc_mark_ht(mrb_state*, struct RClass*); -size_t mrb_gc_mark_ht_size(mrb_state*, struct RClass*); -void mrb_gc_free_ht(mrb_state*, struct RClass*); void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*); #define mrb_field_write_barrier_value(mrb, obj, val) do{\ if ((val.tt >= MRB_TT_OBJECT)) mrb_field_write_barrier((mrb), (obj), mrb_object(val));\ diff --git a/include/mruby/class.h b/include/mruby/class.h index 0713f9b36..62829bd68 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -64,13 +64,15 @@ struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); void mrb_define_method_vm(mrb_state*, struct RClass*, mrb_sym, mrb_value); void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, struct RProc *); +void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, int aspec); struct RClass *mrb_class_outer_module(mrb_state*, struct RClass *); struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym); int mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); -void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, int aspec); +int mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); +struct RClass* mrb_class_real(struct RClass* cl); void mrb_obj_call_init(mrb_state *mrb, mrb_value obj, int argc, mrb_value *argv); diff --git a/include/mruby/data.h b/include/mruby/data.h index f839389f9..d4ce82e40 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -38,6 +38,7 @@ struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void * #define RDATA(obj) ((struct RData *)((obj).value.p)) #define DATA_PTR(d) (RDATA(d)->data) #define DATA_TYPE(d) (RDATA(d)->type) +void *mrb_get_datatype(mrb_state *mrb, mrb_value, const struct mrb_data_type*); void *mrb_check_datatype(mrb_state *mrb, mrb_value, const struct mrb_data_type*); #define Data_Get_Struct(mrb,obj,type,sval) do {\ sval = mrb_check_datatype(mrb, obj, type); \ diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 94f6a693f..3a15ecd1d 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -9,8 +9,8 @@ struct RHash { MRUBY_OBJECT_HEADER; + struct kh_iv *iv; struct kh_ht *ht; - mrb_value ifnone; }; #define N 624 @@ -47,12 +47,11 @@ void ruby_setenv(mrb_state *mrb, const char *name, const char *value); /* RHASH_TBL allocates st_table if not available. */ #define RHASH(obj) ((struct RHash*)((obj).value.p)) -#define RHASH_TBL(h) mrb_hash_tbl(h) -#define RHASH_H_TBL(h) (RHASH(h)->ht) -#define RHASH_SIZE(h) (RHASH_H_TBL(h)->size) +#define RHASH_TBL(h) (RHASH(h)->ht) +#define RHASH_SIZE(h) (RHASH_TBL(h)->size) #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0) -#define RHASH_IFNONE(h) (RHASH(h)->ifnone) -#define RHASH_PROCDEFAULT(h) (RHASH(h)->ifnone) +#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern(mrb, "ifnone")) +#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h) struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); #define MRB_HASH_PROC_DEFAULT 256 diff --git a/include/mruby/object.h b/include/mruby/object.h index a4d2d2dac..0c3f3a6dd 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -7,8 +7,8 @@ #ifndef MRUBY_OBJECT_H #define MRUBY_OBJECT_H -#define MRUBY_OBJECT_HEADER \ - enum mrb_vtype tt:8;\ +#define MRUBY_OBJECT_HEADER \ + enum mrb_vtype tt:8; \ int color:3;\ unsigned int flags:21;\ struct RClass *c;\ diff --git a/include/mruby/range.h b/include/mruby/range.h index 9a59f645a..1b07ca197 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -21,7 +21,5 @@ struct RRange { mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, int); mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_int err); -int mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); -struct RClass* mrb_class_real(struct RClass* cl); #endif /* MRUBY_RANGE_H */ diff --git a/include/mruby/string.h b/include/mruby/string.h index 5a2c46a99..7ac84bcaf 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -70,7 +70,6 @@ void mrb_str_concat(mrb_state*, mrb_value, mrb_value); mrb_value mrb_obj_to_str(mrb_state*, mrb_value); mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); -mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); /* mrb_str_new */ mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, size_t len); /* mrb_str_resize */ mrb_value mrb_string_value(mrb_state *mrb, mrb_value *ptr); /* StringValue */ mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, int len); @@ -79,8 +78,8 @@ mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); mrb_value mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); mrb_value str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); -char * mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); -char * mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr); +char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); +char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr); mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, long beg, long len); size_t mrb_str_sublen(mrb_state *mrb, mrb_value str, long pos); mrb_value mrb_str_size(mrb_state *mrb, mrb_value self); diff --git a/mrblib/Makefile b/mrblib/Makefile index 10cf654cd..1fd0eb5a7 100644 --- a/mrblib/Makefile +++ b/mrblib/Makefile @@ -12,12 +12,7 @@ RLIB := $(TARGET).rbtmp DEPLIB := $(TARGET).d MRB1 := $(BASEDIR)/*.rb MRBS := $(MRB1) -LIB := ../lib/mruby -ifeq ($(OS),Windows_NT) -LIBR := $(LIB).lib -else -LIBR := $(LIB).a -endif +LIBR := ../lib/libmruby.a # C compiler (gcc) CC = gcc diff --git a/mrblib/enum.rb b/mrblib/enum.rb index b5a387f43..31a94b93f 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -1,8 +1,17 @@ +## +# Enumerable # -# Enumerable -# +# ISO 15.3.2 module Enumerable - # 15.3.2.2.1 + + ## + # Call the given block for each element + # which is yield by +each+. Return false + # if one block value is false. Otherwise + # return true. If no block is given and + # +self+ is false return false. + # + # ISO 15.3.2.2.1 def all?(&block) st = true if block @@ -23,7 +32,14 @@ module Enumerable st end - # 15.3.2.2.2 + ## + # Call the given block for each element + # which is yield by +each+. Return true + # if one block value is true. Otherwise + # return false. If no block is given and + # +self+ is true object return true. + # + # ISO 15.3.2.2.2 def any?(&block) st = false if block @@ -44,7 +60,13 @@ module Enumerable st end - # 15.3.2.2.3 + ## + # Call the given block for each element + # which is yield by +each+. Append all + # values of each block together and + # return this value. + # + # ISO 15.3.2.2.3 def collect(&block) ary = [] self.each{|val| @@ -53,7 +75,14 @@ module Enumerable ary end - # 15.3.2.2.4 + ## + # Call the given block for each element + # which is yield by +each+. Return + # +ifnone+ if no block value was true. + # Otherwise return the first block value + # which had was true. + # + # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) ret = ifnone self.each{|val| @@ -65,7 +94,13 @@ module Enumerable ret end - # 15.3.2.2.5 + ## + # Call the given block for each element + # which is yield by +each+. Pass an + # index to the block which starts at 0 + # and increase by 1 for each element. + # + # ISO 15.3.2.2.5 def each_with_index(&block) i = 0 self.each{|val| @@ -75,7 +110,11 @@ module Enumerable self end - # 15.3.2.2.6 + ## + # Return an array of all elements which + # are yield by +each+. + # + # ISO 15.3.2.2.6 def entries ary = [] self.each{|val| @@ -84,11 +123,19 @@ module Enumerable ary end - # 15.3.2.2.7 - # find(ifnone=nil, &block) + ## + # Alias for find + # + # ISO 15.3.2.2.7 alias find detect - # 15.3.2.2.8 + ## + # Call the given block for each element + # which is yield by +each+. Return an array + # which contains all elements whose block + # value was true. + # + # ISO 15.3.2.2.8 def find_all(&block) ary = [] self.each{|val| @@ -97,7 +144,14 @@ module Enumerable ary end - # 15.3.2.2.9 + ## + # Call the given block for each element + # which is yield by +each+ and which return + # value was true when invoking === with + # +pattern+. Return an array with all + # elements or the respective block values. + # + # ISO 15.3.2.2.9 def grep(pattern, &block) ary = [] self.each{|val| @@ -108,7 +162,13 @@ module Enumerable ary end - # 15.3.2.2.10 + ## + # Return true if at least one element which + # is yield by +each+ returns a true value + # by invoking == with +obj+. Otherwise return + # false. + # + # ISO 15.3.2.2.10 def include?(obj) st = false self.each{|val| @@ -120,7 +180,14 @@ module Enumerable st end - # 15.3.2.2.11 + ## + # Call the given block for each element + # which is yield by +each+. Return value + # is the sum of all block values. Pass + # to each block the current sum and the + # current element. + # + # ISO 15.3.2.2.11 def inject(*args, &block) raise ArgumentError, "too many arguments" if args.size > 2 flag = true # 1st element? @@ -137,11 +204,19 @@ module Enumerable result end - # 15.3.2.2.12 - # map(&block) + ## + # Alias for collect + # + # ISO 15.3.2.2.12 alias map collect - # 15.3.2.2.13 + ## + # Return the maximum value of all elements + # yield by +each+. If no block is given <=> + # will be invoked to define this value. If + # a block is given it will be used instead. + # + # ISO 15.3.2.2.13 def max(&block) flag = true # 1st element? result = nil @@ -161,7 +236,13 @@ module Enumerable result end - # 15.3.2.2.14 + ## + # Return the minimum value of all elements + # yield by +each+. If no block is given <=> + # will be invoked to define this value. If + # a block is given it will be used instead. + # + # ISO 15.3.2.2.14 def min(&block) flag = true # 1st element? result = nil @@ -181,11 +262,22 @@ module Enumerable result end - # 15.3.2.2.15 - # member?(obj) + ## + # Alias for include? + # + # ISO 15.3.2.2.15 alias member? include? - # 15.3.2.2.16 + ## + # Call the given block for each element + # which is yield by +each+. Return an + # array which contains two arrays. The + # first array contains all elements + # whose block value was true. The second + # array contains all elements whose + # block value was false. + # + # ISO 15.3.2.2.16 def partition(&block) ary_T = [] ary_F = [] @@ -199,7 +291,13 @@ module Enumerable [ary_T, ary_F] end - # 15.3.2.2.17 + ## + # Call the given block for each element + # which is yield by +each+. Return an + # array which contains only the elements + # whose block value was false. + # + # ISO 15.3.2.2.17 def reject(&block) ary = [] self.each{|val| @@ -208,11 +306,14 @@ module Enumerable ary end - # 15.3.2.2.18 - # select(&block) + ## + # Alias for find_all. + # + # ISO 15.3.2.2.18 alias select find_all - + ## + # TODO # Does this OK? Please test it. def __sort_sub__(sorted, work, src_ary, head, tail, &block) if head == tail @@ -250,7 +351,15 @@ module Enumerable end # private :__sort_sub__ - # 15.3.2.2.19 + ## + # Return a sorted array of all elements + # which are yield by +each+. If no block + # is given <=> will be invoked on each + # element to define the order. Otherwise + # the given block will be used for + # sorting. + # + # ISO 15.3.2.2.19 def sort(&block) ary = [] self.each{|val| ary.push(val)} @@ -260,7 +369,9 @@ module Enumerable ary end - # 15.3.2.2.20 - # to_a + ## + # Alias for entries. + # + # ISO 15.3.2.2.20 alias to_a entries end diff --git a/mrblib/error.rb b/mrblib/error.rb index 88da1825c..5660d8235 100644 --- a/mrblib/error.rb +++ b/mrblib/error.rb @@ -1,8 +1,13 @@ +## +# Exception # -# Exception -# +# ISO 15.2.22 class Exception - # 15.2.22.4.1 + + ## + # Raise an exception. + # + # ISO 15.2.22.4.1 def self.exception(*args, &block) self.new(*args, &block) end diff --git a/mrblib/string.rb b/mrblib/string.rb index 78f2bea9d..ad7e1fca1 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -1,8 +1,14 @@ +## +# String # -# String -# +# ISO 15.2.10 class String - # 15.2.10.5.15 + + ## + # Calls the given block for each line + # and pass the respective line. + # + # ISO 15.2.10.5.15 def each_line(&block) # expect that str.index accepts an Integer for 1st argument as a byte data offset = 0 @@ -14,7 +20,13 @@ class String self end - # 15.2.10.5.18 + ## + # Replace all matches of +pattern+ with +replacement+. + # Call block (if given) for each match and replace + # +pattern+ with the value of the block. Return the + # final value. + # + # ISO 15.2.10.5.18 def gsub(*args, &block) unless (args.size == 1 && block) || args.size == 2 raise ArgumentError, "wrong number of arguments" @@ -23,7 +35,13 @@ class String ### *** TODO *** ### end - # 15.2.10.5.19 + ## + # Replace all matches of +pattern+ with +replacement+. + # Call block (if given) for each match and replace + # +pattern+ with the value of the block. Modify + # +self+ with the final value. + # + # ISO 15.2.10.5.19 def gsub!(*args, &block) str = self.gsub(*args, &block) if str != self @@ -34,12 +52,23 @@ class String end end - # 15.2.10.5.32 + ## + # Calls the given block for each match of +pattern+ + # If no block is given return an array with all + # matches of +pattern+. + # + # ISO 15.2.10.5.32 def scan(reg, &block) ### *** TODO *** ### end - # 15.2.10.5.36 + ## + # Replace only the first match of +pattern+ with + # +replacement+. Call block (if given) for each + # match and replace +pattern+ with the value of the + # block. Return the final value. + # + # ISO 15.2.10.5.36 def sub(*args, &block) unless (args.size == 1 && block) || args.size == 2 raise ArgumentError, "wrong number of arguments" @@ -48,7 +77,13 @@ class String ### *** TODO *** ### end - # 15.2.10.5.37 + ## + # Replace only the first match of +pattern+ with + # +replacement+. Call block (if given) for each + # match and replace +pattern+ with the value of the + # block. Modify +self+ with the final value. + # + # ISO 15.2.10.5.37 def sub!(*args, &block) str = self.sub(*args, &block) if str != self @@ -59,6 +94,9 @@ class String end end + ## + # Call the given block for each character of + # +self+. def each_char(&block) pos = 0 while(pos < self.size) @@ -68,6 +106,8 @@ class String self end + ## + # Call the given block for each byte of +self+. def each_byte(&block) bytes = self.unpack("C*") pos = 0 @@ -78,6 +118,9 @@ class String self end + ## + # Modify +self+ by replacing the content of +self+ + # at the position +pos+ with +value+. def []=(pos, value) b = self[0, pos] a = self[pos+1..-1] @@ -86,7 +129,10 @@ class String end end -# include modules +## +# String is comparable +# +# ISO 15.2.10.3 module Comparable; end class String include Comparable diff --git a/src/Makefile b/src/Makefile index 1b139389a..11a00b41c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,12 +4,7 @@ # project-specific macros # extension of the executable-file is modifiable(.exe .out ...) BASEDIR = . -TARGET := ../lib/mruby -ifeq ($(OS),Windows_NT) -LIB := $(TARGET).lib -else -LIB := $(TARGET).a -endif +TARGET := ../lib/libmruby.a YSRC := $(BASEDIR)/parse.y YC := $(BASEDIR)/y.tab.c EXCEPT1 := $(YC) $(BASEDIR)/minimain.c @@ -40,11 +35,11 @@ ALL_CFLAGS = -Wall -Werror-implicit-function-declaration $(CFLAGS) # generic build targets, rules .PHONY : all -all : $(LIB) +all : $(TARGET) @echo "make: built targets of `pwd`" # executable constructed using linker from object files -$(LIB) : $(OBJS) $(OBJY) +$(TARGET) : $(OBJS) $(OBJY) $(AR) r $@ $(OBJS) $(OBJY) -include $(OBJS:.o=.d) $(OBJY:.o=.d) @@ -65,6 +60,6 @@ $(YC) : $(YSRC) .PHONY : clean #cleandep clean : @echo "make: removing targets, objects and depend files of `pwd`" - -rm -f $(LIB) $(OBJS) $(OBJY) $(YC) + -rm -f $(TARGET) $(OBJS) $(OBJY) $(YC) -rm -f $(OBJS:.o=.d) $(OBJY:.o=.d) -rm -f $(patsubst %.c,%.o,$(EXCEPT1)) $(patsubst %.c,%.d,$(EXCEPT1)) diff --git a/src/class.c b/src/class.c index 366bde96d..1e2ac7aa0 100644 --- a/src/class.c +++ b/src/class.c @@ -309,9 +309,9 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f } void -mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int apec) +mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, int aspec) { - return mrb_define_method_id(mrb, c, mrb_intern(mrb, name), func, apec); + return mrb_define_method_id(mrb, c, mrb_intern(mrb, name), func, aspec); } void @@ -348,7 +348,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value *p; p = va_arg(ap, mrb_value*); - *p = (argc > i) ? *sp : mrb_nil_value(); + *p = *sp; i++; sp++; } break; @@ -357,7 +357,22 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_int *p; p = va_arg(ap, mrb_int*); - *p = (argc > i) ? mrb_fixnum(*sp) : 0; + switch (sp->tt) { + case MRB_TT_FIXNUM: + *p = mrb_fixnum(*sp); + break; + case MRB_TT_FLOAT: + *p = (mrb_int)mrb_float(*sp); + break; + default: + { + mrb_value tmp; + + tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); + *p = mrb_fixnum(tmp); + } + break; + } i++; sp++; } break; @@ -368,13 +383,18 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_float*); switch (sp->tt) { case MRB_TT_FLOAT: - *p = (argc > i) ? mrb_float(*sp) : 0; + *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: - *p = (argc > i) ? (mrb_float)mrb_fixnum(*sp) : 0; + *p = (mrb_float)mrb_fixnum(*sp); break; default: - // error + { + mrb_value tmp; + + tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); + *p = mrb_float(tmp); + } break; } i++; sp++; @@ -502,6 +522,7 @@ mrb_mod_include(mrb_state *mrb, mrb_value klass) mrb_value mod; mrb_get_args(mrb, "o", &mod); + mrb_check_type(mrb, mod, MRB_TT_MODULE); mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); return mod; } @@ -835,7 +856,8 @@ mrb_check_inheritable(mrb_state *mrb, struct RClass *super) * \param super a class from which the new class derives. * \exception TypeError \a super is not inheritable. * \exception TypeError \a super is the Class class. - */struct RClass * + */ +struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super) { struct RClass *c; diff --git a/src/codegen.c b/src/codegen.c index b0f5abc1a..89af78c63 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1893,7 +1893,6 @@ loop_break(codegen_scope *s, node *tree) if (tree) { codegen(s, tree, VAL); - printf("break op %d\n", cursp()); pop(); } diff --git a/src/error.c b/src/error.c index d18311633..f57f0e5e6 100644 --- a/src/error.c +++ b/src/error.c @@ -16,7 +16,6 @@ #include "mruby/numeric.h" #include "mruby/variable.h" #include "mruby/string.h" -#include "eval_intern.h" #include "mruby/class.h" #define warn_printf printf @@ -18,13 +18,6 @@ #define TRUE 1 #endif -void -ruby_xfree(void *x) -{ - //if (x) - // vm_xfree(&mrb_objspace, x); -} - struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const struct mrb_data_type *type) { @@ -38,6 +31,18 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const str } void * +mrb_get_datatype(mrb_state *mrb, mrb_value obj, const struct mrb_data_type *type) +{ + if (SPECIAL_CONST_P(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + return NULL; + } + if (DATA_TYPE(obj) != type) { + return NULL; + } + return DATA_PTR(obj); +} + +void * mrb_check_datatype(mrb_state *mrb, mrb_value obj, const struct mrb_data_type *type) { static const char mesg[] = "wrong argument type %s (expected %s)"; diff --git a/src/eval_intern.h b/src/eval_intern.h deleted file mode 100644 index 4324f26cc..000000000 --- a/src/eval_intern.h +++ /dev/null @@ -1,223 +0,0 @@ -/* -** eval_intern.h - -** -** See Copyright Notice in mruby.h -*/ - -#ifndef RUBY_EVAL_INTERN_H -#define RUBY_EVAL_INTERN_H - -//#include "ruby/ruby.h" -#include "mruby.h" -#define HAVE_STRING_H -//#include "vm_core.h" -#include "node.h" - -/* other frame flag */ -#define VM_FRAME_FLAG_PASSED 0x0100 -#define PASS_PASSED_BLOCK_TH(th) do { \ - (th)->passed_block = GC_GUARDED_PTR_REF((mrb_block_t *)(th)->cfp->lfp[0]); \ - (th)->cfp->flag |= VM_FRAME_FLAG_PASSED; \ -} while (0) - -#define PASS_PASSED_BLOCK() do { \ - mrb_thread_t * const __th__ = GET_THREAD(); \ - PASS_PASSED_BLOCK_TH(__th__); \ -} while (0) - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif - -#include <stdio.h> -#include <setjmp.h> - -#ifdef __APPLE__ -#include <crt_externs.h> -#endif - -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -# ifndef atarist -# ifndef alloca -# define alloca __builtin_alloca -# endif -# endif /* atarist */ -#else -# ifdef HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifdef _AIX -#pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca(); -# endif -# endif /* AIX */ -# endif /* HAVE_ALLOCA_H */ -#endif /* __GNUC__ */ - -#ifndef HAVE_STRING_H -char *strrchr(const char *, const char); -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_NET_SOCKET_H -#include <net/socket.h> -#endif - - - -#include <sys/types.h> -#include <signal.h> -#include <errno.h> - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif - -/* - Solaris sys/select.h switches select to select_large_fdset to support larger - file descriptors if FD_SETSIZE is larger than 1024 on 32bit environment. - But Ruby doesn't change FD_SETSIZE because fd_set is allocated dynamically. - So following definition is required to use select_large_fdset. -*/ -#ifdef HAVE_SELECT_LARGE_FDSET -#define select(n, r, w, e, t) select_large_fdset(n, r, w, e, t) -#endif - -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif - -#include <sys/stat.h> - -#define SAVE_ROOT_JMPBUF(th, stmt) do \ - if (ruby_setjmp((th)->root_jmpbuf) == 0) { \ - stmt; \ - } while (0) - -#define TH_PUSH_TAG(th) do { \ - mrb_thread_t * const _th = th; \ - struct mrb_vm_tag _tag; \ - _tag.tag = 0; \ - _tag.prev = _th->tag; \ - _th->tag = &_tag; - -#define TH_POP_TAG() \ - _th->tag = _tag.prev; \ -} while (0) - -#define TH_POP_TAG2() \ - _th->tag = _tag.prev - -#define PUSH_TAG() TH_PUSH_TAG(GET_THREAD()) -#define POP_TAG() TH_POP_TAG() - -#define TH_EXEC_TAG() ruby_setjmp(_th->tag->buf) - -#define EXEC_TAG() \ - TH_EXEC_TAG() - -#define TH_JUMP_TAG(th, st) do { \ - ruby_longjmp(th->tag->buf,(st)); \ -} while (0) - -//#define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), st) - -enum ruby_tag_type { - RUBY_TAG_RETURN = 0x1, - RUBY_TAG_BREAK = 0x2, - RUBY_TAG_NEXT = 0x3, - RUBY_TAG_RETRY = 0x4, - RUBY_TAG_REDO = 0x5, - RUBY_TAG_RAISE = 0x6, - RUBY_TAG_THROW = 0x7, - RUBY_TAG_FATAL = 0x8, - RUBY_TAG_MASK = 0xf -}; -#define TAG_RETURN RUBY_TAG_RETURN -#define TAG_BREAK RUBY_TAG_BREAK -#define TAG_NEXT RUBY_TAG_NEXT -#define TAG_RETRY RUBY_TAG_RETRY -#define TAG_REDO RUBY_TAG_REDO -#define TAG_RAISE RUBY_TAG_RAISE -#define TAG_THROW RUBY_TAG_THROW -#define TAG_FATAL RUBY_TAG_FATAL -#define TAG_MASK RUBY_TAG_MASK - -#define NEW_THROW_OBJECT(val, pt, st) \ - ((mrb_value)mrb_node_newnode(NODE_LIT, (mrb_value)(val), (mrb_value)(pt), (mrb_value)(st))) -//#define SET_THROWOBJ_CATCH_POINT(obj, val) -// (RNODE((obj))->u2.value = (val)) -//#define SET_THROWOBJ_STATE(obj, val) -// (RNODE((obj))->u3.value = (val)) - -#define GET_THROWOBJ_VAL(obj) ((mrb_value)RNODE((obj))->u1.value) -#define GET_THROWOBJ_CATCH_POINT(obj) ((mrb_value*)RNODE((obj))->u2.value) -#define GET_THROWOBJ_STATE(obj) ((int)RNODE((obj))->u3.value) - -#define SCOPE_TEST(f) (mrb_vm_cref()->nd_visi & (f)) -#define SCOPE_CHECK(f) (mrb_vm_cref()->nd_visi == (f)) -#define SCOPE_SET(f) (mrb_vm_cref()->nd_visi = (f)) - -#define sysstack_error mrb_fixnum_value(0) - -#define CHECK_STACK_OVERFLOW(mrb, cfp, margin) do \ - if ((mrb_value *)((char *)(((mrb_value *)(cfp)->sp) + (margin)) + sizeof(mrb_control_frame_t)) >= ((mrb_value *)cfp)) { \ - mrb_exc_raise(mrb, sysstack_error); \ - } \ -while (0) - -void mrb_thread_cleanup(void); -void mrb_thread_wait_other_threads(void); - -enum { - RAISED_EXCEPTION = 1, - RAISED_STACKOVERFLOW = 2, - RAISED_NOMEMORY = 4 -}; -//int rb_threadptr_set_raised(mrb_thread_t *th); -//int rb_threadptr_reset_raised(mrb_thread_t *th); -#define mrb_thread_raised_set(th, f) ((th)->raised_flag |= (f)) -#define mrb_thread_raised_reset(th, f) ((th)->raised_flag &= ~(f)) -#define mrb_thread_raised_p(th, f) (((th)->raised_flag & (f)) != 0) -#define mrb_thread_raised_clear(th) ((th)->raised_flag = 0) - -//mrb_value mrb_f_eval(int argc, mrb_value *argv, mrb_value self); -//mrb_value mrb_make_exception(int argc, mrb_value *argv); -#ifndef NORETURN -# define NORETURN(x) x -#endif -#ifndef DEPRECATED -# define DEPRECATED(x) x -#endif - -NORETURN(void mrb_fiber_start(void)); - -NORETURN(void rb_print_undef(mrb_value, mrb_sym, int)); -NORETURN(void rb_vm_localjump_error(const char *,mrb_value, int)); -NORETURN(void rb_vm_jump_tag_but_local_jump(int, mrb_value)); -//NORETURN(void mrb_raise_method_missing(mrb_thread_t *th, int argc, mrb_value *argv, -// mrb_value obj, int call_status)); - -mrb_value mrb_vm_make_jump_tag_but_local_jump(int state, mrb_value val); -NODE *mrb_vm_cref(void); -//mrb_value rb_vm_call_cfunc(mrb_value recv, mrb_value (*func)(mrb_value), mrb_value arg, const mrb_block_t *blockptr, mrb_value filename, mrb_value filepath); -void mrb_vm_set_progname(mrb_value filename); -void mrb_thread_terminate_all(mrb_state *mrb); -//mrb_value mrb_vm_top_self(); -mrb_value mrb_vm_cbase(void); -//int mrb_vm_get_sourceline(const mrb_control_frame_t *); -void mrb_trap_restore_mask(void); - -#endif /* RUBY_EVAL_INTERN_H */ @@ -345,7 +345,8 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) break; case MRB_TT_HASH: - mrb_gc_mark_ht(mrb, (struct RClass*)obj); + mrb_gc_mark_iv(mrb, (struct RObject*)obj); + mrb_gc_mark_ht(mrb, (struct RHash*)obj); break; case MRB_TT_STRING: @@ -422,6 +423,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj) break; case MRB_TT_HASH: + mrb_gc_free_iv(mrb, (struct RObject*)obj); mrb_gc_free_ht(mrb, (struct RClass*)obj); break; @@ -530,7 +532,8 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj) break; case MRB_TT_HASH: - children += mrb_gc_mark_ht_size(mrb, (struct RClass*)obj); + children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); + children += mrb_gc_mark_ht_size(mrb, (struct RHash*)obj); break; case MRB_TT_PROC: @@ -29,4 +29,16 @@ typedef struct { } as; } RVALUE; +void mrb_gc_mark_gv(mrb_state*); +void mrb_gc_free_gv(mrb_state*); +void mrb_gc_mark_iv(mrb_state*, struct RObject*); +size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); +void mrb_gc_free_iv(mrb_state*, struct RObject*); +void mrb_gc_mark_mt(mrb_state*, struct RClass*); +size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); +void mrb_gc_free_mt(mrb_state*, struct RClass*); +void mrb_gc_mark_ht(mrb_state*, struct RHash*); +size_t mrb_gc_mark_ht_size(mrb_state*, struct RHash*); +void mrb_gc_free_ht(mrb_state*, struct RHash*); + #endif /* MRUBY_GC_H */ diff --git a/src/hash.c b/src/hash.c index 078faf1d3..cb34dae75 100644 --- a/src/hash.c +++ b/src/hash.c @@ -9,10 +9,8 @@ #include "mruby/khash.h" #include "mruby/class.h" #include "mruby/array.h" -#include "error.h" #include "mruby/string.h" -#include "mruby/numeric.h" -#include "mruby/struct.h" +#include "mruby/variable.h" #include "st.h" #include <errno.h> #include <string.h> @@ -66,12 +64,11 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) #define KEY(key) mrb_hash_ht_key(mrb, key) void -mrb_gc_mark_ht(mrb_state *mrb, struct RClass *c) +mrb_gc_mark_ht(mrb_state *mrb, struct RHash *c) { khiter_t k; khash_t(ht) *h = ((struct RHash*)c)->ht; - mrb_gc_mark_value(mrb, ((struct RHash*)c)->ifnone); if (!h) return; for (k = kh_begin(h); k != kh_end(h); k++) if (kh_exist(h, k)) { @@ -86,9 +83,6 @@ mrb_gc_mark_ht_size(mrb_state *mrb, struct RClass *c) size_t ht_size = 0; khash_t(ht) *h = ((struct RHash*)c)->ht; - /* ((struct RHash*)c)->ifnone */ - ht_size++; - /* ((struct RHash*)c)->ht */ if (h) ht_size += kh_size(h)*2; @@ -112,7 +106,7 @@ mrb_hash_new_capa(mrb_state *mrb, size_t capa) h = mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); h->ht = kh_init(ht, mrb); kh_resize(ht, h->ht, capa); - h->ifnone = mrb_nil_value(); + h->iv = 0; return mrb_obj_value(h); } @@ -125,7 +119,7 @@ mrb_hash_new(mrb_state *mrb, int capa) mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) /* mrb_hash_aref */ /* mrb_hash_lookup */ { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; if (h) { @@ -138,15 +132,13 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) /* mrb_hash_aref */ if (MRB_RHASH_PROCDEFAULT_P(hash)) { return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); } - else { - return RHASH_IFNONE(hash); - } + return RHASH_IFNONE(hash); } mrb_value mrb_hash_getWithDef(mrb_state *mrb, mrb_value hash, mrb_value vkey, mrb_value def) /* mrb_hash_lookup2 */ { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; if (h) { @@ -166,7 +158,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) /* mr khiter_t k; mrb_hash_modify(mrb, hash); - h = RHASH_H_TBL(hash); + h = RHASH_TBL(hash); k = kh_get(ht, h, key); if (k == kh_end(h)) { @@ -201,18 +193,6 @@ retry: } } -static mrb_value -hash_s_new(mrb_state *mrb, mrb_value klass) -{ - mrb_value *argv; - int argc; - - mrb_get_args(mrb, "*", &argv, &argc); - mrb_value hash = mrb_hash_new_capa(mrb, 0); - mrb_obj_call_init(mrb, hash, argc, argv); - return hash; -} - mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash) { @@ -224,7 +204,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) ret->ht = kh_init(ht, mrb); if (!RHASH_EMPTY_P(hash)) { - h = RHASH_H_TBL(hash); + h = RHASH_TBL(hash); ret_h = ret->ht; for (k = kh_begin(h); k != kh_end(h); k++) { @@ -247,10 +227,10 @@ mrb_hash_modify_check(mrb_state *mrb, mrb_value hash) khash_t(ht) * mrb_hash_tbl(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); - if (!RHASH_H_TBL(hash)) { - RHASH_H_TBL(hash) = kh_init(ht, mrb); + if (!RHASH_TBL(hash)) { + RHASH_TBL(hash) = kh_init(ht, mrb); } return h; } @@ -301,21 +281,20 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_init_core(mrb_state *mrb, mrb_value hash) { - mrb_value block; + mrb_value block, ifnone; mrb_value *argv; int argc; mrb_get_args(mrb, "o*", &block, &argv, &argc); mrb_hash_modify(mrb, hash); - if (mrb_nil_p(block)) { if (argc > 0) { if (argc != 1) mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - RHASH_IFNONE(hash) = argv[0]; + ifnone = argv[0]; } else { - RHASH_IFNONE(hash) = mrb_nil_value(); + ifnone = mrb_nil_value(); } } else { @@ -323,9 +302,9 @@ mrb_hash_init_core(mrb_state *mrb, mrb_value hash) mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; - RHASH_PROCDEFAULT(hash) = block; + ifnone = block; } - + mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone); return hash; } @@ -497,7 +476,7 @@ mrb_hash_set_default(mrb_state *mrb, mrb_value hash) mrb_get_args(mrb, "o", &ifnone); mrb_hash_modify(mrb, hash); - RHASH_IFNONE(hash) = ifnone; + mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone); RHASH(hash)->flags &= ~(MRB_HASH_PROC_DEFAULT); return ifnone; @@ -541,10 +520,23 @@ mrb_hash_default_proc(mrb_state *mrb, mrb_value hash) * h["cat"] #=> "catcat" */ +static mrb_value +mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) +{ + mrb_value ifnone; + mrb_get_args(mrb, "o", &ifnone); + + mrb_hash_modify(mrb, hash); + mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone); + RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; + + return ifnone; +} + mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; mrb_value delVal; @@ -610,7 +602,7 @@ struct shift_var { static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; mrb_value delKey, delVal; mrb_value result; @@ -625,8 +617,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) delVal = mrb_hash_delete_key(mrb, hash, delKey); result = mrb_hash_new(mrb, 1); - k = kh_put(ht, RHASH_H_TBL(result), KEY(delKey)); - kh_value(RHASH_H_TBL(result), k) = delVal; + k = kh_put(ht, RHASH_TBL(result), KEY(delKey)); + kh_value(RHASH_TBL(result), k) = delVal; return result; } } @@ -688,7 +680,7 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_value mrb_hash_values_at(mrb_state *mrb, int argc, mrb_value *argv, mrb_value hash) { - mrb_value result = mrb_ary_new_capa(mrb, argc);//mrb_ary_new2(argc); + mrb_value result = mrb_ary_new_capa(mrb, argc); long i; for (i=0; i<argc; i++) { @@ -747,7 +739,7 @@ mrb_hash_values_at(mrb_state *mrb, int argc, mrb_value *argv, mrb_value hash) static mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); kh_clear(ht, h); return hash; @@ -799,7 +791,7 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_replace(mrb_state *mrb, mrb_value hash) { - mrb_value hash2; + mrb_value hash2, ifnone; khash_t(ht) *h2; khiter_t k; @@ -810,7 +802,7 @@ mrb_hash_replace(mrb_state *mrb, mrb_value hash) if (mrb_obj_equal(mrb, hash, hash2)) return hash; mrb_hash_clear(mrb, hash); - h2 = RHASH_H_TBL(hash2); + h2 = RHASH_TBL(hash2); if (h2) { for (k = kh_begin(h2); k != kh_end(h2); k++) { if (kh_exist(h2, k)) @@ -820,11 +812,13 @@ mrb_hash_replace(mrb_state *mrb, mrb_value hash) if (MRB_RHASH_PROCDEFAULT_P(hash2)) { RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; - RHASH_PROCDEFAULT(hash) = RHASH_PROCDEFAULT(hash2); + ifnone = RHASH_PROCDEFAULT(hash2); } else { - RHASH_IFNONE(hash) = RHASH_IFNONE(hash2); + ifnone = RHASH_IFNONE(hash2); } + mrb_iv_set(mrb, hash, mrb_intern(mrb, "ifnone"), ifnone); + return hash; } @@ -845,7 +839,7 @@ mrb_hash_replace(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_H_TBL(self); + khash_t(ht) *h = RHASH_TBL(self); if (!h) return mrb_fixnum_value(0); return mrb_fixnum_value(kh_size(h)); @@ -864,7 +858,7 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_H_TBL(self); + khash_t(ht) *h = RHASH_TBL(self); khiter_t k; if (h) { for (k = kh_begin(h); k != kh_end(h); k++) @@ -941,12 +935,12 @@ static mrb_value inspect_hash(mrb_state *mrb, mrb_value hash, int recur) { mrb_value str, str2; - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; - if (recur) return mrb_str_new2(mrb, "{...}"); + if (recur) return mrb_str_new_cstr(mrb, "{...}"); - str = mrb_str_new2(mrb, "{"); + str = mrb_str_new_cstr(mrb, "{"); if (h && kh_size(h) > 0) { for (k = kh_begin(h); k != kh_end(h); k++) { int ai; @@ -987,7 +981,7 @@ static mrb_value mrb_hash_inspect(mrb_state *mrb, mrb_value hash) { if (RHASH_EMPTY_P(hash)) - return mrb_str_new2(mrb, "{}"); + return mrb_str_new_cstr(mrb, "{}"); return inspect_hash(mrb, hash, 0); } @@ -1021,7 +1015,7 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; mrb_value ary = mrb_ary_new(mrb); @@ -1053,7 +1047,7 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; mrb_value ary = mrb_ary_new(mrb); @@ -1072,7 +1066,7 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_has_keyWithKey(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; if (h) { @@ -1115,7 +1109,7 @@ mrb_hash_has_key(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_has_valueWithvalue(mrb_state *mrb, mrb_value hash, mrb_value value) { - khash_t(ht) *h = RHASH_H_TBL(hash); + khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; if (h) { @@ -1158,8 +1152,8 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) static mrb_value recursive_eql(mrb_state *mrb, mrb_value hash, mrb_value dt, int recur) { - khash_t(ht) *h1 = RHASH_H_TBL(hash); - khash_t(ht) *h2 = RHASH_H_TBL(dt); + khash_t(ht) *h1 = RHASH_TBL(hash); + khash_t(ht) *h2 = RHASH_TBL(dt); khiter_t k1, k2; mrb_value key1; @@ -1388,7 +1382,6 @@ mrb_init_hash(mrb_state *mrb) h = mrb->hash_class = mrb_define_class(mrb, "Hash", mrb->object_class); MRB_SET_INSTANCE_TT(h, MRB_TT_HASH); - //mrb_define_class_method(mrb, h, "new", hash_s_new, ARGS_ANY()); mrb_include_module(mrb, h, mrb_class_get(mrb, "Enumerable")); mrb_define_method(mrb, h, "==", mrb_hash_equal, ARGS_REQ(1)); /* 15.2.13.4.1 */ mrb_define_method(mrb, h, "[]", mrb_hash_aget, ARGS_REQ(1)); /* 15.2.13.4.2 */ @@ -1397,6 +1390,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "default", mrb_hash_default, ARGS_ANY()); /* 15.2.13.4.5 */ mrb_define_method(mrb, h, "default=", mrb_hash_set_default, ARGS_REQ(1)); /* 15.2.13.4.6 */ mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,ARGS_NONE()); /* 15.2.13.4.7 */ + mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,ARGS_REQ(1)); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, ARGS_REQ(1)); /* core of 15.2.13.4.8 */ //mrb_define_method(mrb, h, "each", mrb_hash_each_pair, ARGS_NONE()); /* 15.2.13.4.9 */ /* move to mrblib\hash.rb */ //mrb_define_method(mrb, h, "each_key", mrb_hash_each_key, ARGS_NONE()); /* 15.2.13.4.10 */ /* move to mrblib\hash.rb */ diff --git a/src/init.c b/src/init.c index 9dbdc44d1..347c6919f 100644 --- a/src/init.c +++ b/src/init.c @@ -98,6 +98,7 @@ mrb_init_core(mrb_state *mrb) #endif mrb_init_exception(mrb); mrb_init_print(mrb); + mrb_init_time(mrb); #ifdef MANDEL mrb_define_method(mrb, mrb->kernel_module, "pow", mpow, ARGS_REQ(2)); diff --git a/src/kernel.c b/src/kernel.c index 8d7b38880..76ef9fa69 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -638,6 +638,13 @@ mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) return mrb_yield_with_self(mrb, b, 0, 0, self); } +int +mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) +{ + if (mrb_obj_class(mrb, obj) == c) return TRUE; + return FALSE; +} + /* 15.3.1.3.19 */ /* * call-seq: @@ -646,8 +653,8 @@ mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) * Returns <code>true</code> if <i>obj</i> is an instance of the given * class. See also <code>Object#kind_of?</code>. */ -mrb_value -rb_obj_is_instance_of(mrb_state *mrb, mrb_value self) +static mrb_value +obj_is_instance_of(mrb_state *mrb, mrb_value self) { mrb_value arg; @@ -1417,7 +1424,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, ARGS_NONE()); /* 15.3.1.3.17 */ mrb_define_method(mrb, krn, "instance_eval", mrb_obj_instance_eval, ARGS_ANY()); /* 15.3.1.3.18 */ - mrb_define_method(mrb, krn, "instance_of?", rb_obj_is_instance_of, ARGS_REQ(1)); /* 15.3.1.3.19 */ + mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, ARGS_REQ(1)); /* 15.3.1.3.19 */ mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, ARGS_REQ(1)); /* 15.3.1.3.20 */ mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, ARGS_REQ(1)); /* 15.3.1.3.21 */ mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, ARGS_REQ(2)); /* 15.3.1.3.22 */ diff --git a/src/object.c b/src/object.c index 6c0e944a8..4e479a119 100644 --- a/src/object.c +++ b/src/object.c @@ -310,7 +310,7 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, f, "|", false_or, ARGS_REQ(1)); /* 15.2.6.3.4 */ } -mrb_value +static mrb_value convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, int raise) { mrb_sym m = 0; diff --git a/src/proc.c b/src/proc.c index b77c7342a..c579d8d17 100644 --- a/src/proc.c +++ b/src/proc.c @@ -31,7 +31,7 @@ mrb_closure_new(mrb_state *mrb, mrb_irep *irep) if (!mrb->ci->env) { e = mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass *) mrb->ci->proc->env); - e->flags= (unsigned int)irep->nlocals; + e->flags= (unsigned int)mrb->ci->proc->body.irep->nlocals; e->mid = mrb->ci->mid; e->cioff = mrb->ci - mrb->cibase; e->stack = mrb->stack; diff --git a/src/range.c b/src/range.c index 020ae7ec0..f298d336e 100644 --- a/src/range.c +++ b/src/range.c @@ -31,23 +31,6 @@ mrb_value mrb_exec_recursive_paired(mrb_state *mrb, mrb_value (*func) (mrb_state mrb_value obj, mrb_value paired_obj, void* arg); int printf (const char*, ...); -/*--------- <1.8.7>object.c ---------> */ - -/* - * call-seq: - * obj.instance_of?(class) => true or false - * - * Returns <code>true</code> if <i>obj</i> is an instance of the given - * class. See also <code>Object#kind_of?</code>. - */ - -int -mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) -{ - if (mrb_obj_class(mrb, obj) == c) return TRUE; - return FALSE; -} -/*--------- <1.8.7>object.c ---------< */ mrb_value mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, int excl) diff --git a/src/time.c b/src/time.c new file mode 100644 index 000000000..a71d83058 --- /dev/null +++ b/src/time.c @@ -0,0 +1,600 @@ +/* +** time.c - Time class +** +** See Copyright Notice in mruby.h +*/ + + +#include "mruby.h" +#include <string.h> +#include <stdio.h> +#include <time.h> +#include "mruby/class.h" +#include "mruby/data.h" + +/* Time class configuration */ +#undef USE_GETTIMEOFDAY /* C99 does not have gettimeofday */ +#define USE_GETTIMEOFDAY /* need gettimeofday to retrieve microseconds */ +#undef USE_GMTIME_R /* C99 does not have reentrant gmtime_r */ +#define USE_GMTIME_R /* use reentrant gmtime_r */ + +#ifdef USE_GETTIMEOFDAY +#include <sys/time.h> +#endif +#ifndef USE_GMTIME_R +#define gmtime_r(t,r) gmtime(t) +#define localtime_r(t,r) localtime(t) +#endif + +/* Since we are limited to using ISO C89, this implementation is based +* on time_t. That means the resolution of time is only precise to the +* second level. Also, there are only 2 timezones, namely UTC and LOCAL. +*/ + +#ifndef mrb_bool_value +#define mrb_bool_value(val) ((val) ? mrb_true_value() : mrb_false_value()) +#endif + + +enum mrb_timezone { + MRB_TIMEZONE_NONE = 0, + MRB_TIMEZONE_UTC = 1, + MRB_TIMEZONE_LOCAL = 2, + MRB_TIMEZONE_LAST = 3 +}; + +static const char *timezone_names[] = { + "none", + "UTC", + "LOCAL", + NULL +}; + +static const char *mon_names[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +static const char *wday_names[] = { + "Sun", "Mon", "Tus", "Wed", "Thu", "Fri", "Sat", +}; + +struct mrb_time { + time_t sec; + time_t usec; + enum mrb_timezone timezone; + struct tm datetime; +}; + +static void +mrb_time_free(mrb_state *mrb, void *ptr) +{ + mrb_free(mrb, ptr); +} + +static struct mrb_data_type mrb_time_type = { "Time", mrb_time_free }; + +/** Updates the datetime of a mrb_time based on it's timezone and +seconds setting. Returns self on cussess, NULL of failure. */ +struct mrb_time* +mrb_time_update_datetime(struct mrb_time *self) +{ + struct tm *aid; + + if(self->timezone == MRB_TIMEZONE_UTC) { + aid = gmtime_r(&self->sec, &self->datetime); + } + else { + aid = localtime_r(&self->sec, &self->datetime); + } + if(!aid) return NULL; +#ifndef USE_GMTIME_R + self->datetime = *aid; // copy data +#endif + + return self; +} + +static mrb_value +mrb_time_wrap(mrb_state *mrb, struct RClass *tc, struct mrb_time *tm) +{ + return mrb_obj_value(Data_Wrap_Struct(mrb, tc, &mrb_time_type, tm)); +} + + +/* Allocates a mrb_time object and initializes it. */ +static struct mrb_time* +mrb_time_alloc(mrb_state *mrb, mrb_float seconds, enum mrb_timezone timezone) +{ + struct mrb_time *tm; + + tm = mrb_malloc(mrb, sizeof(struct mrb_time)); + tm->sec = (time_t)seconds; + tm->usec = (seconds - tm->sec) * 1.0e6; + tm->timezone = timezone; + mrb_time_update_datetime(tm); + + return tm; +} + +static mrb_value +mrb_time_make(mrb_state *mrb, struct RClass *c, mrb_float seconds, enum mrb_timezone timezone) +{ + return mrb_time_wrap(mrb, c, mrb_time_alloc(mrb, seconds, timezone)); +} + +/* Allocates a new Time object with given millis value. */ +static mrb_value +mrb_time_now(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_malloc(mrb, sizeof(*tm)); +#ifdef USE_GETTIMEOFDAY + { + struct timeval tv; + + gettimeofday(&tv, NULL); + tm->sec = tv.tv_sec; + tm->usec = tv.tv_usec; + } +#else + tm->sec = time(NULL); + tm->usec = 0; +#endif + tm->timezone = MRB_TIMEZONE_LOCAL; + mrb_time_update_datetime(tm); + return mrb_time_wrap(mrb, mrb_class_ptr(self), tm); +} + +/* 15.2.19.6.1 */ +/* Creates an instance of time at the given time in seconds, etc. */ +static mrb_value +mrb_time_at(mrb_state *mrb, mrb_value self) +{ + mrb_float f; + + mrb_get_args(mrb, "f", &f); + return mrb_time_make(mrb, mrb_class_ptr(self), f, MRB_TIMEZONE_LOCAL); +} + +static struct mrb_time* +time_mktime(mrb_state *mrb, int ayear, int amonth, int aday, + int ahour, int amin, int asec, int ausec, + enum mrb_timezone timezone) +{ + time_t nowsecs; + struct tm nowtime; + + nowtime.tm_year = (int)ayear - 1900; + nowtime.tm_mon = (int)amonth - 1; + nowtime.tm_mday = (int)aday; + nowtime.tm_hour = (int)ahour; + nowtime.tm_min = (int)amin; + nowtime.tm_sec = (int)asec; + nowtime.tm_isdst = -1; + nowsecs = mktime(&nowtime); + if (nowsecs < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); + } + + return mrb_time_alloc(mrb, nowsecs+ausec/10e6, timezone); +} + +/* 15.2.19.6.2 */ +/* Creates an instance of time at the given time in UTC. */ +static mrb_value +mrb_time_gm(mrb_state *mrb, mrb_value self) +{ + mrb_float ayear = 0.0, amonth = 1.0, aday = 1.0, ahour = 0.0, + amin = 0.0, asec = 0.0, ausec = 0.0; + + mrb_get_args(mrb, "fffffff", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + return mrb_time_wrap(mrb, mrb_class_ptr(self), + time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_UTC)); +} + + +/* 15.2.19.6.3 */ +/* Creates an instance of time at the given time in local time zone. */ +static mrb_value +mrb_time_local(mrb_state *mrb, mrb_value self) +{ + mrb_float ayear = 0.0, amonth = 1.0, aday = 1.0, ahour = 0.0, + amin = 0.0, asec = 0.0, ausec = 0.0; + + mrb_get_args(mrb, "fffffff", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + return mrb_time_wrap(mrb, mrb_class_ptr(self), + time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL)); +} + + +static mrb_value +mrb_time_eq(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + struct mrb_time *tm1, *tm2; + + mrb_get_args(mrb, "o", &other); + tm1 = mrb_get_datatype(mrb, self, &mrb_time_type); + tm2 = mrb_get_datatype(mrb, other, &mrb_time_type); + if (!tm1 || !tm2) return mrb_false_value(); + if (tm1->sec == tm2->sec && tm1->usec == tm2->usec) { + return mrb_true_value(); + } + return mrb_false_value(); +} + +static mrb_value +mrb_time_cmp(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + struct mrb_time *tm1, *tm2; + + mrb_get_args(mrb, "o", &other); + tm1 = mrb_get_datatype(mrb, self, &mrb_time_type); + tm2 = mrb_get_datatype(mrb, other, &mrb_time_type); + if (!tm1 || !tm2) return mrb_nil_value(); + if (tm1->sec > tm2->sec) { + return mrb_fixnum_value(1); + } + else if (tm1->sec < tm2->sec) { + return mrb_fixnum_value(-1); + } + /* tm1->sec == tm2->sec */ + if (tm1->usec > tm2->usec) { + return mrb_fixnum_value(1); + } + else if (tm1->usec < tm2->usec) { + return mrb_fixnum_value(-1); + } + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_time_plus(mrb_state *mrb, mrb_value self) +{ + mrb_float f; + struct mrb_time *tm; + + mrb_get_args(mrb, "f", &f); + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + f += tm->sec; + f += (mrb_float)tm->usec / 1.0e6; + return mrb_time_make(mrb, mrb_obj_class(mrb, self), f, tm->timezone); +} + +static mrb_value +mrb_time_minus(mrb_state *mrb, mrb_value self) +{ + mrb_float f; + struct mrb_time *tm; + + mrb_get_args(mrb, "f", &f); + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + f -= tm->sec; + f -= (mrb_float)tm->usec / 1.0e6; + return mrb_time_make(mrb, mrb_obj_class(mrb, self), f, tm->timezone); +} + +/* 15.2.19.7.30 */ +/* Returns week day number of time. */ +static mrb_value +mrb_time_wday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_wday); +} + +/* 15.2.19.7.31 */ +/* Returns year day number of time. */ +static mrb_value +mrb_time_yday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_check_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_yday); +} + +/* 15.2.19.7.32 */ +/* Returns year of time. */ +static mrb_value +mrb_time_year(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_year + 1900); +} + +/* 15.2.19.7.33 */ +/* Returns name of time's timezone. */ +static mrb_value +mrb_time_zone(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + if(tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value(); + if(tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value(); + return mrb_str_new_cstr(mrb, timezone_names[tm->timezone]); +} + +/* 15.2.19.7.4 */ +/* Returns a string that describes the time. */ +static mrb_value +mrb_time_asctime(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + struct tm *d; + char buf[256]; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + d = &tm->datetime; + snprintf(buf, 256, "%s %s %02d %02d:%02d:%02d %s%d", + wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday, + d->tm_hour, d->tm_min, d->tm_sec, + tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "", + d->tm_year + 1900); + return mrb_str_new_cstr(mrb, buf); +} + +/* 15.2.19.7.6 */ +/* Returns the day in the month of the time. */ +static mrb_value +mrb_time_day(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_mday); +} + + +/* 15.2.19.7.7 */ +/* Returns true if daylight saving was applied for this time. */ +static mrb_value +mrb_time_dstp(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_bool_value(tm->datetime.tm_isdst); +} + +/* 15.2.19.7.15 */ +/* Returns hour of time. */ +static mrb_value +mrb_time_hour(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_hour); +} + +/* 15.2.19.7.16 */ +/* Initializes a time by setting the amount of milliseconds since the epoch.*/ +static mrb_value +mrb_time_initialize(mrb_state *mrb, mrb_value self) +{ + mrb_float ayear = 0.0, amonth = 1.0, aday = 1.0, ahour = 0.0, + amin = 0.0, asec = 0.0, ausec = 0.0; + struct mrb_time *tm; + + printf("init\n"); + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if (tm) { + mrb_time_free(mrb, tm); + } + mrb_get_args(mrb, "fffffff", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + DATA_PTR(self) = time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL); + DATA_TYPE(self) = &mrb_time_type; + return self; +} + +/* 15.2.19.7.17(x) */ +/* Initializes a copy of this time object. */ +static mrb_value +mrb_time_initialize_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_value src; + mrb_get_args(mrb, "o", &src); + + if (mrb_obj_equal(mrb, copy, src)) return copy; + if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + memcpy(DATA_PTR(copy), DATA_PTR(src), sizeof(struct mrb_time)); + return copy; +} + +/* 15.2.19.7.18 */ +/* Sets the timezone attribute of the Time object to LOCAL. */ +static mrb_value +mrb_time_localtime(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return self; + tm->timezone = MRB_TIMEZONE_LOCAL; + mrb_time_update_datetime(tm); + return self; +} + +/* 15.2.19.7.19 */ +/* Returns day of month of time. */ +static mrb_value +mrb_time_mday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_mday); +} + +/* 15.2.19.7.20 */ +/* Returns minutes of time. */ +static mrb_value +mrb_time_min(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_min); +} + +/* 15.2.19.7.21 and 15.2.19.7.22 */ +/* Returns month of time. */ +static mrb_value +mrb_time_mon(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_mon + 1); +} + +/* 15.2.19.7.23 */ +/* Returns seconds in minute of time. */ +static mrb_value +mrb_time_sec(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->datetime.tm_sec); +} + + +/* 15.2.19.7.24 */ +/* Returns a Float with the time since the epoch in seconds. */ +static mrb_value +mrb_time_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_float_value((mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6); +} + +/* 15.2.19.7.25 */ +/* Returns a Fixnum with the time since the epoch in seconds. */ +static mrb_value +mrb_time_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->sec); +} + +/* 15.2.19.7.26 */ +/* Returns a Float with the time since the epoch in microseconds. */ +static mrb_value +mrb_time_usec(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_fixnum_value(tm->usec); +} + +/* 15.2.19.7.27 */ +/* Sets the timzeone attribute of the Time object to UTC. */ +static mrb_value +mrb_time_utc(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(tm) { + tm->timezone = MRB_TIMEZONE_UTC; + mrb_time_update_datetime(tm); + } + return self; +} + +/* 15.2.19.7.28 */ +/* Returns true if this time is in the UTC timze zone false if not. */ +static mrb_value +mrb_time_utcp(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + tm = mrb_get_datatype(mrb, self, &mrb_time_type); + if(!tm) return mrb_nil_value(); + return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); +} + + + +void +mrb_init_time(mrb_state *mrb) +{ + struct RClass *tc; + /* ISO 15.2.19.2 */ + tc = mrb_define_class(mrb, "Time", mrb->object_class); + MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA); + mrb_include_module(mrb, tc, mrb_class_get(mrb, "Comparable")); + mrb_define_class_method(mrb, tc, "now", mrb_time_now, ARGS_NONE()); + mrb_define_class_method(mrb, tc, "at", mrb_time_at, ARGS_ANY()); + mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, ARGS_REQ(1)|ARGS_OPT(6)); + mrb_define_class_method(mrb, tc, "local", mrb_time_local, ARGS_REQ(1)|ARGS_OPT(6)); + + mrb_define_method(mrb, tc, "==" , mrb_time_eq , ARGS_REQ(1)); + mrb_define_method(mrb, tc, "<=>" , mrb_time_cmp , ARGS_REQ(1)); + mrb_define_method(mrb, tc, "+" , mrb_time_plus , ARGS_REQ(1)); + mrb_define_method(mrb, tc, "-" , mrb_time_minus , ARGS_REQ(1)); + mrb_define_method(mrb, tc, "to_s" , mrb_time_asctime, ARGS_NONE()); + mrb_define_method(mrb, tc, "asctime", mrb_time_asctime, ARGS_NONE()); + mrb_define_method(mrb, tc, "ctime" , mrb_time_asctime, ARGS_NONE()); + mrb_define_method(mrb, tc, "day" , mrb_time_day , ARGS_NONE()); + mrb_define_method(mrb, tc, "dst?" , mrb_time_dstp , ARGS_NONE()); + mrb_define_method(mrb, tc, "gmt?" , mrb_time_utcp , ARGS_NONE()); + mrb_define_method(mrb, tc, "gmtime" , mrb_time_utc , ARGS_NONE()); + mrb_define_method(mrb, tc, "hour" , mrb_time_hour, ARGS_NONE()); + mrb_define_method(mrb, tc, "localtime", mrb_time_localtime, ARGS_NONE()); + mrb_define_method(mrb, tc, "mday" , mrb_time_mday, ARGS_NONE()); + mrb_define_method(mrb, tc, "min" , mrb_time_min, ARGS_NONE()); + + mrb_define_method(mrb, tc, "mon" , mrb_time_mon, ARGS_NONE()); + mrb_define_method(mrb, tc, "month", mrb_time_mon, ARGS_NONE()); + + mrb_define_method(mrb, tc, "sec" , mrb_time_sec, ARGS_NONE()); + mrb_define_method(mrb, tc, "to_i", mrb_time_to_i, ARGS_NONE()); + mrb_define_method(mrb, tc, "to_f", mrb_time_to_f, ARGS_NONE()); + mrb_define_method(mrb, tc, "usec", mrb_time_usec, ARGS_NONE()); + mrb_define_method(mrb, tc, "utc" , mrb_time_utc, ARGS_NONE()); + mrb_define_method(mrb, tc, "utc?", mrb_time_utcp, ARGS_NONE()); + mrb_define_method(mrb, tc, "wday", mrb_time_wday, ARGS_NONE()); + mrb_define_method(mrb, tc, "yday", mrb_time_yday, ARGS_NONE()); + mrb_define_method(mrb, tc, "year", mrb_time_year, ARGS_NONE()); + mrb_define_method(mrb, tc, "zone", mrb_time_zone, ARGS_NONE()); + + mrb_define_method(mrb, tc, "initialize", mrb_time_initialize, ARGS_REQ(1)); + mrb_define_method(mrb, tc, "initialize_copy", mrb_time_initialize_copy, ARGS_REQ(1)); +} @@ -261,14 +261,33 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value v) return mrb_yield_with_self(mrb, b, 1, &v, mrb->stack[0]); } -void +static void localjump_error(mrb_state *mrb, const char *kind) { char buf[256]; mrb_value exc; snprintf(buf, 256, "unexpected %s", kind); - exc = mrb_exc_new(mrb, E_LOCALJUMP_ERROR, buf, sizeof(buf)); + exc = mrb_exc_new(mrb, E_LOCALJUMP_ERROR, buf, strlen(buf)); + mrb->exc = mrb_object(exc); +} + +static void +argnum_error(mrb_state *mrb, int num) +{ + char buf[256]; + mrb_value exc; + + if (mrb->ci->mid) { + snprintf(buf, 256, "'%s': wrong number of arguments (%d for %d)", + mrb_sym2name(mrb, mrb->ci->mid), + mrb->ci->argc, num); + } + else { + snprintf(buf, 256, "wrong number of arguments (%d for %d)", + mrb->ci->argc, num); + } + exc = mrb_exc_new(mrb, E_ARGUMENT_ERROR, buf, strlen(buf)); mrb->exc = mrb_object(exc); } @@ -717,7 +736,9 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) ci->target_class = m->target_class; ci->proc = m; if (m->env) { - ci->mid = m->env->mid; + if (m->env->mid) { + ci->mid = m->env->mid; + } if (!m->env->stack) { m->env->stack = mrb->stack; } @@ -895,10 +916,8 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) { if (argc >= 0) { if (argc < m1 + m2 || (r == 0 && argc > len)) { - fprintf(stderr, "'%s': wrong number of arguments (%d for %d)\n", - mrb_sym2name(mrb, mrb->ci->mid), - mrb->ci->argc, m1+m2); - exit(1); + argnum_error(mrb, m1+m2); + goto L_RAISE; } } } @@ -992,6 +1011,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) case OP_R_RETURN: if (proc->env->cioff < 0) { localjump_error(mrb, "return"); + goto L_RAISE; } ci = mrb->ci = mrb->cibase + proc->env->cioff; break; diff --git a/test/test_time.rb b/test/test_time.rb new file mode 100644 index 000000000..737b7e060 --- /dev/null +++ b/test/test_time.rb @@ -0,0 +1,50 @@ +$ok = 0 +$failed = 0 +$ftest = [] + +def assert(str = "Assertion failed") + if(!yield) + $ftest.push(str) + $failed += 1 + print "F" + else + $ok += 1 + print "." + end +end + +def report() + print "\n" + $ftest.each do |str| + puts("Test Failed: #{str}"); + end + $total = $ok + $failed + puts "Ran #{$total} tests: #{$ok} OK and #{$failed} failed." +end + +doom = Time.gm(2012, 12, 23) +assert("Time.gm") { doom } +assert("gm year") { doom.year == 2012 } +assert("gm month") { doom.month == 12 } +assert("gm day") { doom.mday == 23 } + +t0 = Time.new +assert("Can create time.") { t0 } + +t1 = Time.at(1300000000.0e6).utc +p t1.asctime +assert("asctime") { t1.asctime == "Sun Mar 13 16:06:40 UTC 2011" } +assert("usec") { t1.usec == 0 } +assert("to_i") { t1.to_i == 1300000000 } +assert("to_f") { t1.to_f == 1300000000.0 } +assert("utc?") { t1.utc? } +assert("zone") { t1.zone == "UTC" } +assert("wday") { t1.wday == 0 } +assert("yday") { t1.yday == 71 } +assert("year") { t1.year == 2011 } + +t2 = Time.new(7.0e6) +t1.initialize_copy(t2) +assert("initialize_copy") { t1 == t2 } + +report() diff --git a/tools/mrbc/Makefile b/tools/mrbc/Makefile index 282032c76..1137baa03 100644 --- a/tools/mrbc/Makefile +++ b/tools/mrbc/Makefile @@ -5,13 +5,11 @@ # extension of the executable-file is modifiable(.exe .out ...) BASEDIR := ../../src TARGET := ../../bin/mrbc -LIB := ../../lib/mruby +LIBR := ../../lib/libmruby.a ifeq ($(OS),Windows_NT) EXE := $(TARGET).exe -LIBR := $(LIB).lib else EXE := $(TARGET) -LIBR := $(LIB).a endif EXCEPT1 := OBJ0 := $(patsubst %.c,%.o,$(wildcard $(BASEDIR)/../tools/mrbc/*.c)) diff --git a/tools/mruby/Makefile b/tools/mruby/Makefile index 7b7eb83be..19140aabb 100644 --- a/tools/mruby/Makefile +++ b/tools/mruby/Makefile @@ -5,13 +5,11 @@ # extension of the executable-file is modifiable(.exe .out ...) BASEDIR = ../../src TARGET := ../../bin/mruby -LIB := ../../lib/mruby +LIBR := ../../lib/libmruby.a ifeq ($(OS),Windows_NT) EXE := $(TARGET).exe -LIBR := $(LIB).lib else EXE := $(TARGET) -LIBR := $(LIB).a endif OBJ0 := $(patsubst %.c,%.o,$(wildcard $(BASEDIR)/../tools/mruby/*.c)) #OBJ1 := $(patsubst %.c,%.o,$(filter-out $(EXCEPT1),$(wildcard $(BASEDIR)/*.c))) |
