summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby.h14
-rw-r--r--include/mruby/class.h4
-rw-r--r--include/mruby/data.h1
-rw-r--r--include/mruby/hash.h11
-rw-r--r--include/mruby/object.h4
-rw-r--r--include/mruby/range.h2
-rw-r--r--include/mruby/string.h5
-rw-r--r--mrblib/Makefile7
-rw-r--r--mrblib/enum.rb167
-rw-r--r--mrblib/error.rb11
-rw-r--r--mrblib/string.rb64
-rw-r--r--src/Makefile13
-rw-r--r--src/class.c38
-rw-r--r--src/codegen.c1
-rw-r--r--src/error.c1
-rw-r--r--src/etc.c19
-rw-r--r--src/eval_intern.h223
-rw-r--r--src/gc.c7
-rw-r--r--src/gc.h12
-rw-r--r--src/hash.c116
-rw-r--r--src/init.c1
-rw-r--r--src/kernel.c13
-rw-r--r--src/object.c2
-rw-r--r--src/proc.c2
-rw-r--r--src/range.c17
-rw-r--r--src/time.c600
-rw-r--r--src/vm.c34
-rw-r--r--test/test_time.rb50
-rw-r--r--tools/mrbc/Makefile4
-rw-r--r--tools/mruby/Makefile4
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
diff --git a/src/etc.c b/src/etc.c
index 477a78ebc..eac71459c 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -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 */
diff --git a/src/gc.c b/src/gc.c
index 06360036a..b5c94c9bd 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -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:
diff --git a/src/gc.h b/src/gc.h
index 3c18905d3..61f8ce96a 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -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));
+}
diff --git a/src/vm.c b/src/vm.c
index 9915200de..9c79a7afe 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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)))