From b05d736b49a6d3a99b7f75c74ffd9b6613c453d3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 29 May 2015 17:01:44 +0900 Subject: update mrblib/*.rb files to conform (some of) Rubocop checks --- mrblib/array.rb | 4 ++-- mrblib/hash.rb | 4 ++-- mrblib/kernel.rb | 2 +- mrblib/numeric.rb | 8 ++++---- mrblib/range.rb | 2 +- mrblib/string.rb | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index bd8d5930f..83a42c62d 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -34,7 +34,7 @@ class Array return to_enum :each_index unless block_given? idx = 0 - while(idx < length) + while idx < length block.call(idx) idx += 1 end @@ -75,7 +75,7 @@ class Array self[size - 1] = nil # allocate idx = 0 - while(idx < size) + while idx < size self[idx] = (block)? block.call(idx): obj idx += 1 end diff --git a/mrblib/hash.rb b/mrblib/hash.rb index e7c51fb1f..cb52c1ffe 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -10,7 +10,7 @@ class Hash # hash. # # ISO 15.2.13.4.1 - def == (hash) + def ==(hash) return true if self.equal?(hash) begin hash = hash.to_hash @@ -54,7 +54,7 @@ class Hash # # ISO 15.2.13.4.8 def delete(key, &block) - if block && ! self.has_key?(key) + if block && !self.has_key?(key) block.call(key) else self.__delete(key) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 8c9b122f2..38af3b310 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -27,7 +27,7 @@ module Kernel def loop(&block) return to_enum :loop unless block - while(true) + while true yield end rescue StopIteration diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 1f44a2c81..cf608b04b 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -48,7 +48,7 @@ module Integral return to_enum(:downto, num) unless block_given? i = self.to_i - while(i >= num) + while i >= num block.call(i) i -= 1 end @@ -89,7 +89,7 @@ module Integral return to_enum(:upto, num) unless block_given? i = self.to_i - while(i <= num) + while i <= num block.call(i) i += 1 end @@ -106,12 +106,12 @@ module Integral i = if num.kind_of? Float then self.to_f else self end if step > 0 - while(i <= num) + while i <= num block.call(i) i += step end else - while(i >= num) + while i >= num block.call(i) i += step end diff --git a/mrblib/range.rb b/mrblib/range.rb index 1ec9ac508..64fa0cb6c 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -32,7 +32,7 @@ class Range return self if (val <=> last) > 0 - while((val <=> last) < 0) + while (val <=> last) < 0 block.call(val) val = val.succ end diff --git a/mrblib/string.rb b/mrblib/string.rb index 1d9ea9e6a..90aad5d32 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(&block) # expect that str.index accepts an Integer for 1st argument as a byte data offset = 0 - while(pos = self.index(0x0a, offset)) + while pos = self.index(0x0a, offset) block.call(self[offset, pos + 1 - offset]) offset = pos + 1 end @@ -106,7 +106,7 @@ class String # +self+. def each_char(&block) pos = 0 - while(pos < self.size) + while pos < self.size block.call(self[pos]) pos += 1 end @@ -118,7 +118,7 @@ class String def each_byte(&block) bytes = self.bytes pos = 0 - while(pos < bytes.size) + while pos < bytes.size block.call(bytes[pos]) pos += 1 end -- cgit v1.2.3 From 2554fd9c945d5b5281a52d40146b348353e3707c Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 29 May 2015 11:29:11 +0200 Subject: remove unreachable code It's just a copy of the code in the previous case (NODE_CALL). --- src/codegen.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/codegen.c b/src/codegen.c index 222dec9b6..6f1f75e88 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -957,13 +957,6 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) gen_vmassignment(s, tree->car, sp, val); break; - push(); - gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); - pop(); - if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); - } - break; /* splat without assignment */ case NODE_NIL: break; -- cgit v1.2.3 From ba3a0c22a52111da15c9dfea534a68d3fffd78e3 Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 29 May 2015 12:17:13 +0200 Subject: add multiple assignment with rest tests --- test/t/syntax.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 5ce4e0a63..41e49d938 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -219,6 +219,21 @@ assert('Splat without assignment') do assert_equal 1, a end +assert('multiple assignment (rest)') do + *a = 0 + assert_equal [0], a +end + +assert('multiple assignment (rest+post)') do + *a, b = 0, 1, 2 + *c, d = 3 + + assert_equal [0, 1], a + assert_equal [2], b + assert_equal [], c + assert_equal [3], d +end + assert('Return values of case statements') do a = [] << case 1 when 3 then 2 -- cgit v1.2.3 From 59ea323976557408ba1c5f694213c7a31bbb6e39 Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 29 May 2015 14:51:48 +0200 Subject: check if outer is a class or module For modules this check didn't exist yet. Also call #inspect. --- src/class.c | 24 +++++++++++++++--------- test/t/class.rb | 5 +++++ test/t/module.rb | 4 ++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/class.c b/src/class.c index 3246564ec..35c3aa040 100644 --- a/src/class.c +++ b/src/class.c @@ -131,6 +131,19 @@ mrb_class_outer_module(mrb_state *mrb, struct RClass *c) return mrb_class_ptr(outer); } +static void +check_if_class_or_module(mrb_state *mrb, mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + return; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + } +} + static struct RClass* define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer) { @@ -160,6 +173,7 @@ mrb_define_module(mrb_state *mrb, const char *name) MRB_API struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { + check_if_class_or_module(mrb, outer); return define_module(mrb, id, mrb_class_ptr(outer)); } @@ -232,15 +246,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id else { s = 0; } - switch (mrb_type(outer)) { - case MRB_TT_CLASS: - case MRB_TT_SCLASS: - case MRB_TT_MODULE: - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", outer); - break; - } + check_if_class_or_module(mrb, outer); c = define_class(mrb, id, s, mrb_class_ptr(outer)); mrb_class_inherited(mrb, mrb_class_real(c->super), c); diff --git a/test/t/class.rb b/test/t/class.rb index d4ecf99d0..720fd37fa 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -383,3 +383,8 @@ assert('class variable and class << self style class method') do assert_equal("value", ClassVariableTest.class_variable) end + +assert('class with non-class/module outer raises TypeError') do + assert_raise(TypeError) { class 0::C1; end } + assert_raise(TypeError) { class []::C2; end } +end diff --git a/test/t/module.rb b/test/t/module.rb index 9852328ce..ecb969475 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -533,3 +533,7 @@ assert('Module#module_function') do assert_true M.respond_to?(:modfunc) end +assert('module with non-class/module outer raises TypeError') do + assert_raise(TypeError) { module 0::M1 end } + assert_raise(TypeError) { module []::M2 end } +end -- cgit v1.2.3 From 9ef4bbb10d827fb41edc8c2984e0b80fcdbea900 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 31 May 2015 18:29:26 +0900 Subject: update test/t/syntax.rb to success on CRuby --- test/t/syntax.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 41e49d938..070fcbe3b 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -229,9 +229,9 @@ assert('multiple assignment (rest+post)') do *c, d = 3 assert_equal [0, 1], a - assert_equal [2], b + assert_equal 2, b assert_equal [], c - assert_equal [3], d + assert_equal 3, d end assert('Return values of case statements') do -- cgit v1.2.3 From 6a1978c7e1f58d3cda8cca390d65e5f64580b169 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 31 May 2015 18:30:37 +0900 Subject: fix OP_APOST bug for no pre arg cases; fix #2810 --- src/vm.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/vm.c b/src/vm.c index dd0d0ba43..1f3b05df2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2125,33 +2125,28 @@ RETRY_TRY_BLOCK: int pre = GETARG_B(i); int post = GETARG_C(i); + struct RArray *ary; + int len, idx; + if (!mrb_array_p(v)) { - regs[a++] = mrb_ary_new_capa(mrb, 0); + v = mrb_ary_new_from_values(mrb, 1, ®s[a]); + } + ary = mrb_ary_ptr(v); + len = ary->len; + if (len > pre + post) { + regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); while (post--) { - SET_NIL_VALUE(regs[a]); - a++; + regs[a++] = ary->ptr[len-post-1]; } } else { - struct RArray *ary = mrb_ary_ptr(v); - int len = ary->len; - int idx; - - if (len > pre + post) { - regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre); - while (post--) { - regs[a++] = ary->ptr[len-post-1]; - } + regs[a++] = mrb_ary_new_capa(mrb, 0); + for (idx=0; idx+preptr[pre+idx]; } - else { - regs[a++] = mrb_ary_new_capa(mrb, 0); - for (idx=0; idx+preptr[pre+idx]; - } - while (idx < post) { - SET_NIL_VALUE(regs[a+idx]); - idx++; - } + while (idx < post) { + SET_NIL_VALUE(regs[a+idx]); + idx++; } } ARENA_RESTORE(mrb, ai); -- cgit v1.2.3 From 5cd877be7f875546dcc03d80aeeddd4bbbcffe3d Mon Sep 17 00:00:00 2001 From: cremno Date: Sun, 31 May 2015 13:30:49 +0200 Subject: fix masgn nosplat array rhs bug The rest lhs variable has to be an empty array if rhs is an array with less elements than pre + post lhs variables. The codegen generated OP_ARRAY with an invalid length (such as 127 for *a, b = []) because rn was negative. --- src/codegen.c | 8 +++++++- test/t/syntax.rb | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/codegen.c b/src/codegen.c index 6f1f75e88..be630b9a8 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1615,8 +1615,14 @@ codegen(codegen_scope *s, node *tree, int val) } } if (t->car) { /* rest (len - pre - post) */ - int rn = len - post - n; + int rn; + if (len < post + n) { + rn = 0; + } + else { + rn = len - post - n; + } genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); gen_assignment(s, t->car, cursp(), NOVAL); n += rn; diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 070fcbe3b..dc1a4a3b9 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -234,6 +234,20 @@ assert('multiple assignment (rest+post)') do assert_equal 3, d end +assert('multiple assignment (nosplat array rhs)') do + a, *b = [] + *c, d = [0] + e, *f, g = [1, 2] + + assert_nil a + assert_equal [], b + assert_equal [], c + assert_equal 0, d + assert_equal 1, e + assert_equal [], f + assert_equal 2, g +end + assert('Return values of case statements') do a = [] << case 1 when 3 then 2 -- cgit v1.2.3 From bd2686d82d233774003fe683e9396f366b152b6d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Jun 2015 00:13:12 +0900 Subject: singleton_class should not be cloned; close #2815 --- src/kernel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel.c b/src/kernel.c index d1e10a7f8..9d056178e 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -330,6 +330,9 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) if (mrb_immediate_p(self)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } + if (mrb_type(self) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); + } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); clone = mrb_obj_value(p); -- cgit v1.2.3 From 7284d1d295c0eaaa2e36ce52e9dd65f8221ed8b2 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Sun, 31 May 2015 23:26:33 -0400 Subject: Update mruby.h.md Added documentation of more of the C API functions found inside mruby.h --- doc/api/mruby.h.md | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index f537b6482..36712e5dc 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -67,3 +67,142 @@ char|mruby type|retrieve types|note `?`|optional given|`mrb_bool`|True if preceding argument is given. Used to check optional argument is given. The passing variadic arguments must be a pointer of retrieving type. + +### mrb_define_class +```C +MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*); +``` +Creates a new class. If you're creating a gem it may look something like this: + +```C +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_class; + example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` +### mrb_define_method + +```C +MRB_API void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +``` + +Creates a global function in ruby. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Executing example commad!"); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + mrb_define_method(mrb, mrb->kernel_module, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +Or maybe you want to create a class method for a class? It might look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like pizza..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_class; + example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); + mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` +### mrb_define_module + +```C +MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); +``` + +Creates a module in ruby. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like tacos..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_module; + example_module = mrb_define_module(mrb, "Example_Module"); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +### mrb_define_module_function + +```C +MRB_API void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); +``` + +Defines a module function. If you're creating a gem it may look something like this: + + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like hot wings..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + struct RClass *example_module; + example_module = mrb_define_module(mrb, "Example_Module"); + mrb_define_module_function(mrb, example_module, "example_method", example_method, MRB_ARGS_NONE()); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + +### mrb_define_const + +```C +MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value); +``` + +Defines a constant. If you're creating a gem it may look something like this: + +```C +mrb_value example_method(mrb_state* mrb, mrb_value self){ + puts("Examples are like hot wings..."); + return self; +} + +void mrb_example_gem_init(mrb_state* mrb) { + mrb_define_const(mrb, mrb->kernel_module, "EXAPMLE_CONSTANT", mrb_fixnum_value(0x00000001)); +} + +void mrb_example_gem_final(mrb_state* mrb) { + //free(TheAnimals); +} +``` + + + + + + + + + -- cgit v1.2.3 From 4959e4958abca0404c60fe54a4c700bfd1a25eb6 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Sun, 31 May 2015 23:27:12 -0400 Subject: Update mruby.h.md --- doc/api/mruby.h.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 36712e5dc..88fa2c7e5 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -94,7 +94,7 @@ Creates a global function in ruby. If you're creating a gem it may look somethin ```C mrb_value example_method(mrb_state* mrb, mrb_value self){ - puts("Executing example commad!"); + puts("Executing example command!"); return self; } -- cgit v1.2.3 From d90ccd7e6d06582ddb3d3c02e8337551a35b67d8 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Sun, 31 May 2015 23:33:36 -0400 Subject: Update mruby.h.md --- doc/api/mruby.h.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 88fa2c7e5..5a71f5cd4 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -72,7 +72,7 @@ The passing variadic arguments must be a pointer of retrieving type. ```C MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*); ``` -Creates a new class. If you're creating a gem it may look something like this: +Defines a new class. If you're creating a gem it may look something like this: ```C void mrb_example_gem_init(mrb_state* mrb) { @@ -90,7 +90,7 @@ void mrb_example_gem_final(mrb_state* mrb) { MRB_API void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); ``` -Creates a global function in ruby. If you're creating a gem it may look something like this: +Defines a global function in ruby. If you're creating a gem it may look something like this: ```C mrb_value example_method(mrb_state* mrb, mrb_value self){ @@ -131,7 +131,7 @@ void mrb_example_gem_final(mrb_state* mrb) { MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); ``` -Creates a module in ruby. If you're creating a gem it may look something like this: +Defines a module. If you're creating a gem it may look something like this: ```C mrb_value example_method(mrb_state* mrb, mrb_value self){ @@ -198,11 +198,12 @@ void mrb_example_gem_final(mrb_state* mrb) { } ``` +### mrb_str_new_cstr +```C +MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); +``` - - - - +Turns a C string into a Ruby string value. -- cgit v1.2.3 From 1400c6e88ba20a07980770aa9217387a2cbd89bd Mon Sep 17 00:00:00 2001 From: Mav7 Date: Sun, 31 May 2015 23:50:56 -0400 Subject: Added a .md file for value.h --- doc/api/value.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/value.h.md diff --git a/doc/api/value.h.md b/doc/api/value.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 297b6fe6e6f97bc8e4ca95d47fa6b02f7eab6396 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 1 Jun 2015 00:42:23 -0400 Subject: Update value.h.md Wrote documentation for functions found in the value.h file. --- doc/api/value.h.md | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/doc/api/value.h.md b/doc/api/value.h.md index e69de29bb..dd1c4b238 100644 --- a/doc/api/value.h.md +++ b/doc/api/value.h.md @@ -0,0 +1,233 @@ +### mrb_float_value +```C +static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) +``` + +Returns a float in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively +double i = 0.09 could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" +#include "mruby/string.h" + +int +main(void) +{ + mrb_float f = 0.09;// or double i = 0.09; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + +### mrb_fixnum_value + +```C +static inline mrb_value mrb_fixnum_value(mrb_int i) +``` + +Returns a fixnum in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 +could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_int i = 99; // or int i = 99; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_nil_value + +```C +static inline mrb_value mrb_nil_value(void) +``` + +Returns nil in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + +### mrb_false_value + +```C +static inline mrb_value mrb_false_value(void) +``` + +Returns false in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_true_value + +```C +static inline mrb_value mrb_true_value(void) +``` + +Returns true in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` -- cgit v1.2.3 From 1d90018cfa93e63366f4f1fe600bb356dabf8c3b Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 1 Jun 2015 00:44:34 -0400 Subject: Update mruby.h.md --- doc/api/mruby.h.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 5a71f5cd4..8862fee2c 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -207,3 +207,9 @@ MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); Turns a C string into a Ruby string value. +### mrb_value mrb_funcall + +```C +MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); +``` +Call existing ruby functions. -- cgit v1.2.3 From f8b1de0ab47f3f0bae861bf11f73635aa8c02ba6 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 1 Jun 2015 00:54:30 -0400 Subject: Update README.md --- doc/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 131e50515..78dbc087d 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -25,6 +25,6 @@ Header name|Features [mruby/range.h](./mruby.range.h.md)|`Range` class. [mruby/re.h](./mruby.re.h.md)|`Regexp` class. [mruby/string.h](./mruby.string.h.md)|`String` class. -[mruby/value.h](./mruby.value.h.md)|`mrb_value` functions and macros. +[mruby/value.h](./value.h.md)|`mrb_value` functions and macros. [mruby/variable.h](./mruby.variable.h.md)|Functions to access to mruby variables. [mruby/version.h](./mruby.version.h.md)|Macros of mruby version. -- cgit v1.2.3 From b357a6320d8dad87c29b7315d7aa5ed6c4e9fc7a Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 1 Jun 2015 00:59:22 -0400 Subject: Update AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index c78258915..ea8bb5ad6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -26,6 +26,7 @@ Original Authors "mruby developers" are: Hiroshi Mimaki Satoshi Odawara Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. + Ralph Desir(Mav7) Hiroyuki Matsuzaki Yuhei Okazaki Manycolors, Inc. -- cgit v1.2.3 From dc0e33566410489db639a0523b9cb25b04f73080 Mon Sep 17 00:00:00 2001 From: cremno Date: Mon, 1 Jun 2015 13:23:43 +0200 Subject: fix two potential cases of signed integer overflow --- src/array.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/array.c b/src/array.c index 48dc1ff10..1ca7dd2a4 100644 --- a/src/array.c +++ b/src/array.c @@ -298,6 +298,9 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) mrb_int blen; mrb_get_args(mrb, "a", &ptr, &blen); + if (ARY_MAX_SIZE - blen < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } ary = mrb_ary_new_capa(mrb, a1->len + blen); a2 = mrb_ary_ptr(ary); array_copy(a2->ptr, a1->ptr, a1->len); @@ -351,7 +354,9 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); } if (times == 0) return mrb_ary_new(mrb); - + if (ARY_MAX_SIZE / times < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } ary = mrb_ary_new_capa(mrb, a1->len * times); a2 = mrb_ary_ptr(ary); ptr = a2->ptr; -- cgit v1.2.3 From 7e8fb15457f08faf0fd6b7e1d0823140ecee2a60 Mon Sep 17 00:00:00 2001 From: cremno Date: Mon, 1 Jun 2015 13:54:20 +0200 Subject: only generate gets of non-local vars in VAL mode This fixes a crash for code like "#{@a;1}". Unlike CRuby globals are excluded too since mruby doesn't implement hooking. --- src/codegen.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/codegen.c b/src/codegen.c index be630b9a8..16233347c 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -1911,7 +1911,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_GVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); @@ -1920,7 +1920,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_IVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); @@ -1929,7 +1929,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_CVAR: - { + if (val) { int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); @@ -1951,7 +1951,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BACK_REF: - { + if (val) { char buf[2] = { '$' }; mrb_value str; int sym; @@ -1965,7 +1965,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_NTH_REF: - { + if (val) { int sym; mrb_state *mrb = s->mrb; mrb_value fix = mrb_fixnum_value((intptr_t)tree); -- cgit v1.2.3 From b6121adc7dbedcf0e6fd262de536c2f8c9217120 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Jun 2015 21:30:07 +0900 Subject: singleton_class should not be duped; fix #2815 --- src/kernel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel.c b/src/kernel.c index 9d056178e..b5b13f874 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -369,6 +369,9 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) if (mrb_immediate_p(obj)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); } + if (mrb_type(obj) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); + } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); dup = mrb_obj_value(p); init_copy(mrb, dup, obj); -- cgit v1.2.3 From 6460ef77bcceb17d80d1b46a07b28fada19737c8 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 6 Apr 2015 15:20:13 +0900 Subject: Compile mruby compiler as mrbgem. Compiler codes is moved to "mruby-compiler". Executable `mrbc` is moved to "mruby-bin-mrbc". --- Rakefile | 1 - bintest/mrbc.rb | 12 - mrbgems/mruby-bin-mrbc/mrbgem.rake | 16 + mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c | 337 ++ mrbgems/mruby-compiler/bintest/mrbc.rb | 12 + mrbgems/mruby-compiler/core/codegen.c | 2720 +++++++++++++ mrbgems/mruby-compiler/core/keywords | 50 + mrbgems/mruby-compiler/core/lex.def | 212 + mrbgems/mruby-compiler/core/node.h | 117 + mrbgems/mruby-compiler/core/parse.y | 6420 ++++++++++++++++++++++++++++++ mrbgems/mruby-compiler/mrbgem.rake | 40 + mrbgems/mruby-eval/mrbgem.rake | 2 + src/codegen.c | 2720 ------------- src/keywords | 50 - src/lex.def | 212 - src/mruby_core.rake | 63 +- src/node.h | 117 - src/parse.y | 6420 ------------------------------ tasks/mruby_build.rake | 41 +- tools/mrbc/mrbc.c | 337 -- tools/mrbc/mrbc.rake | 14 - travis_config.rb | 4 + 22 files changed, 9971 insertions(+), 9946 deletions(-) delete mode 100644 bintest/mrbc.rb create mode 100644 mrbgems/mruby-bin-mrbc/mrbgem.rake create mode 100644 mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c create mode 100644 mrbgems/mruby-compiler/bintest/mrbc.rb create mode 100644 mrbgems/mruby-compiler/core/codegen.c create mode 100644 mrbgems/mruby-compiler/core/keywords create mode 100644 mrbgems/mruby-compiler/core/lex.def create mode 100644 mrbgems/mruby-compiler/core/node.h create mode 100644 mrbgems/mruby-compiler/core/parse.y create mode 100644 mrbgems/mruby-compiler/mrbgem.rake delete mode 100644 src/codegen.c delete mode 100644 src/keywords delete mode 100644 src/lex.def delete mode 100644 src/node.h delete mode 100644 src/parse.y delete mode 100644 tools/mrbc/mrbc.c delete mode 100644 tools/mrbc/mrbc.rake diff --git a/Rakefile b/Rakefile index 66f54a4e2..0f33c5ee8 100644 --- a/Rakefile +++ b/Rakefile @@ -21,7 +21,6 @@ end # load custom rules load "#{MRUBY_ROOT}/src/mruby_core.rake" load "#{MRUBY_ROOT}/mrblib/mrblib.rake" -load "#{MRUBY_ROOT}/tools/mrbc/mrbc.rake" load "#{MRUBY_ROOT}/tasks/mrbgems.rake" load "#{MRUBY_ROOT}/tasks/libmruby.rake" diff --git a/bintest/mrbc.rb b/bintest/mrbc.rb deleted file mode 100644 index b016378a1..000000000 --- a/bintest/mrbc.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'tempfile' - -assert('Compiling multiple files without new line in last line. #2361') do - a, b, out = Tempfile.new('a.rb'), Tempfile.new('b.rb'), Tempfile.new('out.mrb') - a.write('module A; end') - a.flush - b.write('module B; end') - b.flush - result = `bin/mrbc -c -o #{out.path} #{a.path} #{b.path} 2>&1` - assert_equal "bin/mrbc:#{a.path}:Syntax OK", result.chomp - assert_equal 0, $?.exitstatus -end diff --git a/mrbgems/mruby-bin-mrbc/mrbgem.rake b/mrbgems/mruby-bin-mrbc/mrbgem.rake new file mode 100644 index 000000000..e710b5a49 --- /dev/null +++ b/mrbgems/mruby-bin-mrbc/mrbgem.rake @@ -0,0 +1,16 @@ +MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler executable' + + spec.add_dependency 'mruby-compiler', :core => 'mruby-compiler' + + exec = exefile("#{build.build_dir}/bin/mrbc") + mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten + + file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t| + build.linker.run t.name, t.prerequisites + end + + build.bins << 'mrbc' unless build.bins.find { |v| v == 'mrbc' } +end diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c new file mode 100644 index 000000000..f27f87a5d --- /dev/null +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include "mruby.h" +#include "mruby/compile.h" +#include "mruby/dump.h" +#include "mruby/proc.h" + +#define RITEBIN_EXT ".mrb" +#define C_EXT ".c" + +struct mrbc_args { + int argc; + char **argv; + int idx; + const char *prog; + const char *outfile; + const char *initname; + mrb_bool check_syntax : 1; + mrb_bool verbose : 1; + unsigned int flags : 4; +}; + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-c check syntax only", + "-o place the output into ", + "-v print version number, then turn on verbose mode", + "-g produce debugging information", + "-B binary output in C language format", + "-e generate little endian iseq data", + "-E generate big endian iseq data", + "--verbose run at verbose mode", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches] programfile\n", name); + while (*p) + printf(" %s\n", *p++); +} + +static char * +get_outfilename(mrb_state *mrb, char *infile, const char *ext) +{ + size_t infilelen; + size_t extlen; + char *outfile; + char *p; + + infilelen = strlen(infile); + extlen = strlen(ext); + outfile = (char*)mrb_malloc(mrb, infilelen + extlen + 1); + memcpy(outfile, infile, infilelen + 1); + if (*ext) { + if ((p = strrchr(outfile, '.')) == NULL) + p = outfile + infilelen; + memcpy(p, ext, extlen + 1); + } + + return outfile; +} + +static int +parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) +{ + char *outfile = NULL; + static const struct mrbc_args args_zero = { 0 }; + int i; + + *args = args_zero; + args->argc = argc; + args->argv = argv; + args->prog = argv[0]; + + for (i=1; ioutfile) { + fprintf(stderr, "%s: an output file is already specified. (%s)\n", + args->prog, outfile); + return -1; + } + if (argv[i][2] == '\0' && argv[i+1]) { + i++; + args->outfile = get_outfilename(mrb, argv[i], ""); + } + else { + args->outfile = get_outfilename(mrb, argv[i] + 2, ""); + } + break; + case 'B': + if (argv[i][2] == '\0' && argv[i+1]) { + i++; + args->initname = argv[i]; + } + else { + args->initname = argv[i]+2; + } + if (*args->initname == '\0') { + fprintf(stderr, "%s: function name is not specified.\n", args->prog); + return -1; + } + break; + case 'c': + args->check_syntax = TRUE; + break; + case 'v': + if (!args->verbose) mrb_show_version(mrb); + args->verbose = TRUE; + break; + case 'g': + args->flags |= DUMP_DEBUG_INFO; + break; + case 'E': + args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); + break; + case 'e': + args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); + break; + case 'h': + return -1; + case '-': + if (argv[i][1] == '\n') { + return i; + } + if (strcmp(argv[i] + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i] + 2, "verbose") == 0) { + args->verbose = TRUE; + break; + } + else if (strcmp(argv[i] + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + return -1; + default: + return i; + } + } + else { + break; + } + } + if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) { + fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n", + args->prog, bigendian_p() ? "big" : "little"); + } + return i; +} + +static void +cleanup(mrb_state *mrb, struct mrbc_args *args) +{ + if (args->outfile) + mrb_free(mrb, (void*)args->outfile); + mrb_close(mrb); +} + +static int +partial_hook(struct mrb_parser_state *p) +{ + mrbc_context *c = p->cxt; + struct mrbc_args *args = (struct mrbc_args *)c->partial_data; + const char *fn; + + if (p->f) fclose(p->f); + if (args->idx >= args->argc) { + p->f = NULL; + return -1; + } + fn = args->argv[args->idx++]; + p->f = fopen(fn, "r"); + if (p->f == NULL) { + fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn); + return -1; + } + mrb_parser_set_filename(p, fn); + return 0; +} + +static mrb_value +load_file(mrb_state *mrb, struct mrbc_args *args) +{ + mrbc_context *c; + mrb_value result; + char *input = args->argv[args->idx]; + FILE *infile; + mrb_bool need_close = FALSE; + + c = mrbc_context_new(mrb); + if (args->verbose) + c->dump_result = TRUE; + c->no_exec = TRUE; + if (input[0] == '-' && input[1] == '\0') { + infile = stdin; + } + else { + need_close = TRUE; + if ((infile = fopen(input, "r")) == NULL) { + fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input); + return mrb_nil_value(); + } + } + mrbc_filename(mrb, c, input); + args->idx++; + if (args->idx < args->argc) { + need_close = FALSE; + mrbc_partial_hook(mrb, c, partial_hook, (void*)args); + } + + result = mrb_load_file_cxt(mrb, infile, c); + if (need_close) fclose(infile); + mrbc_context_free(mrb, c); + if (mrb_undef_p(result)) { + return mrb_nil_value(); + } + return result; +} + +static int +dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, struct mrbc_args *args) +{ + int n = MRB_DUMP_OK; + mrb_irep *irep = proc->body.irep; + + if (args->initname) { + n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); + if (n == MRB_DUMP_INVALID_ARGUMENT) { + fprintf(stderr, "%s: invalid C language symbol name\n", args->initname); + } + } + else { + n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp); + } + if (n != MRB_DUMP_OK) { + fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n); + } + return n; +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + int n, result; + struct mrbc_args args; + FILE *wfp; + mrb_value load; + + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mrbc\n", stderr); + return EXIT_FAILURE; + } + + n = parse_args(mrb, argc, argv, &args); + if (n < 0) { + cleanup(mrb, &args); + usage(argv[0]); + return EXIT_FAILURE; + } + if (n == argc) { + fprintf(stderr, "%s: no program file given\n", args.prog); + return EXIT_FAILURE; + } + if (args.outfile == NULL && !args.check_syntax) { + if (n + 1 == argc) { + args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT); + } + else { + fprintf(stderr, "%s: output file should be specified to compile multiple files\n", args.prog); + return EXIT_FAILURE; + } + } + + args.idx = n; + load = load_file(mrb, &args); + if (mrb_nil_p(load)) { + cleanup(mrb, &args); + return EXIT_FAILURE; + } + if (args.check_syntax) { + printf("%s:%s:Syntax OK\n", args.prog, argv[n]); + } + + if (args.check_syntax) { + cleanup(mrb, &args); + return EXIT_SUCCESS; + } + + if (args.outfile) { + if (strcmp("-", args.outfile) == 0) { + wfp = stdout; + } + else if ((wfp = fopen(args.outfile, "wb")) == NULL) { + fprintf(stderr, "%s: cannot open output file:(%s)\n", args.prog, args.outfile); + return EXIT_FAILURE; + } + } + else { + fprintf(stderr, "Output file is required\n"); + return EXIT_FAILURE; + } + result = dump_file(mrb, wfp, args.outfile, mrb_proc_ptr(load), &args); + fclose(wfp); + cleanup(mrb, &args); + if (result != MRB_DUMP_OK) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +void +mrb_init_mrblib(mrb_state *mrb) +{ +} + +#ifndef DISABLE_GEMS +void +mrb_init_mrbgems(mrb_state *mrb) +{ +} + +void +mrb_final_mrbgems(mrb_state *mrb) +{ +} +#endif diff --git a/mrbgems/mruby-compiler/bintest/mrbc.rb b/mrbgems/mruby-compiler/bintest/mrbc.rb new file mode 100644 index 000000000..b016378a1 --- /dev/null +++ b/mrbgems/mruby-compiler/bintest/mrbc.rb @@ -0,0 +1,12 @@ +require 'tempfile' + +assert('Compiling multiple files without new line in last line. #2361') do + a, b, out = Tempfile.new('a.rb'), Tempfile.new('b.rb'), Tempfile.new('out.mrb') + a.write('module A; end') + a.flush + b.write('module B; end') + b.flush + result = `bin/mrbc -c -o #{out.path} #{a.path} #{b.path} 2>&1` + assert_equal "bin/mrbc:#{a.path}:Syntax OK", result.chomp + assert_equal 0, $?.exitstatus +end diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c new file mode 100644 index 000000000..16233347c --- /dev/null +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -0,0 +1,2720 @@ +/* +** codegen.c - mruby code generator +** +** See Copyright Notice in mruby.h +*/ + +#include +#include +#include +#include +#include "mruby.h" +#include "mruby/compile.h" +#include "mruby/proc.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "mruby/debug.h" +#include "node.h" +#include "mruby/opcode.h" +#include "mruby/re.h" +#include "mruby/throw.h" + +typedef mrb_ast_node node; +typedef struct mrb_parser_state parser_state; + +enum looptype { + LOOP_NORMAL, + LOOP_BLOCK, + LOOP_FOR, + LOOP_BEGIN, + LOOP_RESCUE, +}; + +struct loopinfo { + enum looptype type; + int pc1, pc2, pc3, acc; + int ensure_level; + struct loopinfo *prev; +}; + +typedef struct scope { + mrb_state *mrb; + mrb_pool *mpool; + struct mrb_jmpbuf jmp; + + struct scope *prev; + + node *lv; + + int sp; + int pc; + int lastlabel; + int ainfo:15; + mrb_bool mscope:1; + + struct loopinfo *loop; + int ensure_level; + char const *filename; + uint16_t lineno; + + mrb_code *iseq; + uint16_t *lines; + int icapa; + + mrb_irep *irep; + size_t pcapa; + size_t scapa; + size_t rcapa; + + uint16_t nlocals; + uint16_t nregs; + int ai; + + int debug_start_pos; + uint16_t filename_index; + parser_state* parser; +} codegen_scope; + +static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv); +static void scope_finish(codegen_scope *s); +static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); +static void loop_break(codegen_scope *s, node *tree); +static void loop_pop(codegen_scope *s, int val); + +static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); +static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); + +static void codegen(codegen_scope *s, node *tree, int val); +static void raise_error(codegen_scope *s, const char *msg); + +static void +codegen_error(codegen_scope *s, const char *message) +{ + if (!s) return; + while (s->prev) { + codegen_scope *tmp = s->prev; + mrb_pool_close(s->mpool); + s = tmp; + } +#ifdef ENABLE_STDIO + if (s->filename && s->lineno) { + fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); + } + else { + fprintf(stderr, "codegen error: %s\n", message); + } +#endif + MRB_THROW(&s->jmp); +} + +static void* +codegen_palloc(codegen_scope *s, size_t len) +{ + void *p = mrb_pool_alloc(s->mpool, len); + + if (!p) codegen_error(s, "pool memory allocation"); + return p; +} + +static void* +codegen_malloc(codegen_scope *s, size_t len) +{ + void *p = mrb_malloc_simple(s->mrb, len); + + if (!p) codegen_error(s, "mrb_malloc"); + return p; +} + +static void* +codegen_realloc(codegen_scope *s, void *p, size_t len) +{ + p = mrb_realloc_simple(s->mrb, p, len); + + if (!p && len > 0) codegen_error(s, "mrb_realloc"); + return p; +} + +static int +new_label(codegen_scope *s) +{ + s->lastlabel = s->pc; + return s->pc; +} + +static inline int +genop(codegen_scope *s, mrb_code i) +{ + if (s->pc == s->icapa) { + s->icapa *= 2; + s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); + if (s->lines) { + s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); + s->irep->lines = s->lines; + } + } + s->iseq[s->pc] = i; + if (s->lines) { + s->lines[s->pc] = s->lineno; + } + return s->pc++; +} + +#define NOVAL 0 +#define VAL 1 + +static mrb_bool +no_optimize(codegen_scope *s) +{ + if (s && s->parser && s->parser->no_optimize) + return TRUE; + return FALSE; +} + +static int +genop_peep(codegen_scope *s, mrb_code i, int val) +{ + /* peephole optimization */ + if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { + mrb_code i0 = s->iseq[s->pc-1]; + int c1 = GET_OPCODE(i); + int c0 = GET_OPCODE(i0); + + switch (c1) { + case OP_MOVE: + if (GETARG_A(i) == GETARG_B(i)) { + /* skip useless OP_MOVE */ + return 0; + } + if (val) break; + switch (c0) { + case OP_MOVE: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { + /* skip swapping OP_MOVE */ + return 0; + } + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->pc--; + return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); + } + break; + case OP_LOADI: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); + return 0; + } + break; + case OP_ARRAY: + case OP_HASH: + case OP_RANGE: + case OP_AREF: + case OP_GETUPVAR: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); + return 0; + } + break; + case OP_LOADSYM: + case OP_GETGLOBAL: + case OP_GETIV: + case OP_GETCV: + case OP_GETCONST: + case OP_GETSPECIAL: + case OP_LOADL: + case OP_STRING: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); + return 0; + } + break; + case OP_SCLASS: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); + return 0; + } + break; + case OP_LOADNIL: + case OP_LOADSELF: + case OP_LOADT: + case OP_LOADF: + case OP_OCLASS: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); + return 0; + } + break; + default: + break; + } + break; + case OP_SETIV: + case OP_SETCV: + case OP_SETCONST: + case OP_SETMCNST: + case OP_SETGLOBAL: + if (val) break; + if (c0 == OP_MOVE) { + if (GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); + return 0; + } + } + break; + case OP_SETUPVAR: + if (val) break; + if (c0 == OP_MOVE) { + if (GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); + return 0; + } + } + break; + case OP_EPOP: + if (c0 == OP_EPOP) { + s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); + return 0; + } + break; + case OP_POPERR: + if (c0 == OP_POPERR) { + s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); + return 0; + } + break; + case OP_RETURN: + switch (c0) { + case OP_RETURN: + return 0; + case OP_MOVE: + if (GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); + return 0; + } + break; + case OP_SETIV: + case OP_SETCV: + case OP_SETCONST: + case OP_SETMCNST: + case OP_SETUPVAR: + case OP_SETGLOBAL: + s->pc--; + genop_peep(s, i0, NOVAL); + i0 = s->iseq[s->pc-1]; + return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); +#if 0 + case OP_SEND: + if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); + return; + } + break; +#endif + default: + break; + } + break; + case OP_ADD: + case OP_SUB: + if (c0 == OP_LOADI) { + int c = GETARG_sBx(i0); + + if (c1 == OP_SUB) c = -c; + if (c > 127 || c < -127) break; + if (0 <= c) + s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); + else + s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); + return 0; + } + case OP_STRCAT: + if (c0 == OP_STRING) { + mrb_value v = s->irep->pool[GETARG_Bx(i0)]; + + if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { + s->pc--; + return 0; + } + } + break; + case OP_JMPIF: + case OP_JMPNOT: + if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); + return s->pc-1; + } + break; + default: + break; + } + } + return genop(s, i); +} + +static void +scope_error(codegen_scope *s) +{ + exit(EXIT_FAILURE); +} + +static inline void +dispatch(codegen_scope *s, int pc) +{ + int diff = s->pc - pc; + mrb_code i = s->iseq[pc]; + int c = GET_OPCODE(i); + + s->lastlabel = s->pc; + switch (c) { + case OP_JMP: + case OP_JMPIF: + case OP_JMPNOT: + case OP_ONERR: + break; + default: +#ifdef ENABLE_STDIO + fprintf(stderr, "bug: dispatch on non JMP op\n"); +#endif + scope_error(s); + break; + } + s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); +} + +static void +dispatch_linked(codegen_scope *s, int pc) +{ + mrb_code i; + int pos; + + if (!pc) return; + for (;;) { + i = s->iseq[pc]; + pos = GETARG_sBx(i); + dispatch(s, pc); + if (!pos) break; + pc = pos; + } +} + +#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) +static void +push_(codegen_scope *s) +{ + if (s->sp > 511) { + codegen_error(s, "too complex expression"); + } + s->sp++; + nregs_update; +} + +#define push() push_(s) +#define pop_(s) ((s)->sp--) +#define pop() pop_(s) +#define pop_n(n) (s->sp-=(n)) +#define cursp() (s->sp) + +static inline int +new_lit(codegen_scope *s, mrb_value val) +{ + size_t i; + mrb_value *pv; + + switch (mrb_type(val)) { + case MRB_TT_STRING: + for (i=0; iirep->plen; i++) { + mrb_int len; + pv = &s->irep->pool[i]; + + if (mrb_type(*pv) != MRB_TT_STRING) continue; + if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue; + if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0) + return i; + } + break; + case MRB_TT_FLOAT: + for (i=0; iirep->plen; i++) { + pv = &s->irep->pool[i]; + if (mrb_type(*pv) != MRB_TT_FLOAT) continue; + if (mrb_float(*pv) == mrb_float(val)) return i; + } + break; + case MRB_TT_FIXNUM: + for (i=0; iirep->plen; i++) { + pv = &s->irep->pool[i]; + if (!mrb_fixnum_p(*pv)) continue; + if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i; + } + break; + default: + /* should not happen */ + return 0; + } + + if (s->irep->plen == s->pcapa) { + s->pcapa *= 2; + s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa); + } + + pv = &s->irep->pool[s->irep->plen]; + i = s->irep->plen++; + + switch (mrb_type(val)) { + case MRB_TT_STRING: + *pv = mrb_str_pool(s->mrb, val); + break; + + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + *pv = mrb_float_pool(s->mrb, mrb_float(val)); + break; +#endif + case MRB_TT_FIXNUM: + *pv = val; + break; + + default: + /* should not happen */ + break; + } + return i; +} + +static inline int +new_msym(codegen_scope *s, mrb_sym sym) +{ + size_t i, len; + + mrb_assert(s->irep); + + len = s->irep->slen; + if (len > 256) len = 256; + for (i=0; iirep->syms[i] == sym) return i; + if (s->irep->syms[i] == 0) break; + } + if (i == 256) { + codegen_error(s, "too many symbols (max 256)"); + } + s->irep->syms[i] = sym; + if (i == s->irep->slen) s->irep->slen++; + return i; +} + +static inline int +new_sym(codegen_scope *s, mrb_sym sym) +{ + size_t i; + + for (i=0; iirep->slen; i++) { + if (s->irep->syms[i] == sym) return i; + } + if (s->irep->slen > 125 && s->irep->slen < 256) { + s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536); + for (i = 0; i < 256 - s->irep->slen; i++) { + static const mrb_sym mrb_sym_zero = { 0 }; + s->irep->syms[i + s->irep->slen] = mrb_sym_zero; + } + s->irep->slen = 256; + } + s->irep->syms[s->irep->slen] = sym; + return s->irep->slen++; +} + +static int +node_len(node *tree) +{ + int n = 0; + + while (tree) { + n++; + tree = tree->cdr; + } + return n; +} + +#define sym(x) ((mrb_sym)(intptr_t)(x)) +#define lv_name(lv) sym((lv)->car) +static int +lv_idx(codegen_scope *s, mrb_sym id) +{ + node *lv = s->lv; + int n = 1; + + while (lv) { + if (lv_name(lv) == id) return n; + n++; + lv = lv->cdr; + } + return 0; +} + +static void +for_body(codegen_scope *s, node *tree) +{ + codegen_scope *prev = s; + int idx; + struct loopinfo *lp; + node *n2; + mrb_code c; + + /* generate receiver */ + codegen(s, tree->cdr->car, VAL); + /* generate loop-block */ + s = scope_new(s->mrb, s, NULL); + if (s == NULL) { + raise_error(prev, "unexpected scope"); + } + + push(); /* push for a block parameter */ + + lp = loop_push(s, LOOP_FOR); + lp->pc1 = new_label(s); + + /* generate loop variable */ + n2 = tree->car; + genop(s, MKOP_Ax(OP_ENTER, 0x40000)); + if (n2->car && !n2->car->cdr && !n2->cdr) { + gen_assignment(s, n2->car->car, 1, NOVAL); + } + else { + gen_vmassignment(s, n2, 1, VAL); + } + codegen(s, tree->cdr->cdr->car, VAL); + pop(); + if (s->pc > 0) { + c = s->iseq[s->pc-1]; + if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + loop_pop(s, NOVAL); + scope_finish(s); + s = prev; + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); + pop(); + idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); + genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); +} + +static int +lambda_body(codegen_scope *s, node *tree, int blk) +{ + mrb_code c; + codegen_scope *parent = s; + s = scope_new(s->mrb, s, tree->car); + if (s == NULL) { + raise_error(parent, "unexpected scope"); + } + + s->mscope = !blk; + + if (blk) { + struct loopinfo *lp = loop_push(s, LOOP_BLOCK); + lp->pc1 = new_label(s); + } + tree = tree->cdr; + if (tree->car) { + mrb_aspec a; + int ma, oa, ra, pa, ka, kd, ba; + int pos, i; + node *n, *opt; + + ma = node_len(tree->car->car); + n = tree->car->car; + while (n) { + n = n->cdr; + } + oa = node_len(tree->car->cdr->car); + ra = tree->car->cdr->cdr->car ? 1 : 0; + pa = node_len(tree->car->cdr->cdr->cdr->car); + ka = kd = 0; + ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; + + a = ((mrb_aspec)(ma & 0x1f) << 18) + | ((mrb_aspec)(oa & 0x1f) << 13) + | ((ra & 1) << 12) + | ((pa & 0x1f) << 7) + | ((ka & 0x1f) << 2) + | ((kd & 1)<< 1) + | (ba & 1); + s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ + | ((ra & 1) << 5) + | (pa & 0x1f); + genop(s, MKOP_Ax(OP_ENTER, a)); + pos = new_label(s); + for (i=0; i 0) { + genop(s, MKOP_sBx(OP_JMP, 0)); + } + opt = tree->car->cdr->car; + i = 0; + while (opt) { + int idx; + + dispatch(s, pos+i); + codegen(s, opt->car->cdr, VAL); + idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car); + pop(); + genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); + i++; + opt = opt->cdr; + } + if (oa > 0) { + dispatch(s, pos+i); + } + } + codegen(s, tree->cdr->car, VAL); + pop(); + if (s->pc > 0) { + c = s->iseq[s->pc-1]; + if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { + if (s->nregs == 0) { + genop(s, MKOP_A(OP_LOADNIL, 0)); + genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + } + } + if (blk) { + loop_pop(s, NOVAL); + } + scope_finish(s); + return parent->irep->rlen - 1; +} + +static int +scope_body(codegen_scope *s, node *tree, int val) +{ + codegen_scope *scope = scope_new(s->mrb, s, tree->car); + if (scope == NULL) { + raise_error(s, "unexpected scope"); + } + + codegen(scope, tree->cdr, VAL); + if (!s->iseq) { + genop(scope, MKOP_A(OP_STOP, 0)); + } + else if (!val) { + genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + if (scope->nregs == 0) { + genop(scope, MKOP_A(OP_LOADNIL, 0)); + genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); + } + } + scope_finish(scope); + if (!s->irep) { + /* should not happen */ + return 0; + } + return s->irep->rlen - 1; +} + +static mrb_bool +nosplat(node *t) +{ + while (t) { + if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE; + t = t->cdr; + } + return TRUE; +} + +static mrb_sym +attrsym(codegen_scope *s, mrb_sym a) +{ + const char *name; + mrb_int len; + char *name2; + + name = mrb_sym2name_len(s->mrb, a, &len); + name2 = (char *)codegen_palloc(s, + (size_t)len + + 1 /* '=' */ + + 1 /* '\0' */ + ); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + memcpy(name2, name, (size_t)len); + name2[len] = '='; + name2[len+1] = '\0'; + + return mrb_intern(s->mrb, name2, len+1); +} + +static int +gen_values(codegen_scope *s, node *t, int val) +{ + int n = 0; + int is_splat; + + while (t) { + is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */ + if (n >= 127 || is_splat) { + if (val) { + pop_n(n); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + push(); + codegen(s, t->car, VAL); + pop(); pop(); + if (is_splat) { + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + } + else { + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + t = t->cdr; + while (t) { + push(); + codegen(s, t->car, VAL); + pop(); pop(); + if ((intptr_t)t->car->car == NODE_SPLAT) { + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + } + else { + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + t = t->cdr; + } + } + else { + codegen(s, t->car->cdr, NOVAL); + t = t->cdr; + while (t) { + codegen(s, t->car, NOVAL); + t = t->cdr; + } + } + return -1; + } + /* normal (no splat) mode */ + codegen(s, t->car, val); + n++; + t = t->cdr; + } + return n; +} + +#define CALL_MAXARGS 127 + +static void +gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val) +{ + mrb_sym sym = name ? name : sym(tree->cdr->car); + int idx; + int n = 0, noop = 0, sendv = 0, blk = 0; + + codegen(s, tree->car, VAL); /* receiver */ + idx = new_msym(s, sym); + tree = tree->cdr->cdr->car; + if (tree) { + n = gen_values(s, tree->car, VAL); + if (n < 0) { + n = noop = sendv = 1; + push(); + } + } + if (sp) { + if (sendv) { + pop(); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); + push(); + } + else { + genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); + push(); + n++; + } + } + if (tree && tree->cdr) { + noop = 1; + codegen(s, tree->cdr, VAL); + pop(); + } + else { + blk = cursp(); + } + push();pop(); + pop_n(n+1); + { + mrb_int symlen; + const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); + + if (!noop && symlen == 1 && symname[0] == '+') { + genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); + } + else if (!noop && symlen == 1 && symname[0] == '-') { + genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); + } + else if (!noop && symlen == 1 && symname[0] == '*') { + genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '/') { + genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '<') { + genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=') { + genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '>') { + genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=') { + genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=') { + genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); + } + else { + if (sendv) n = CALL_MAXARGS; + if (blk > 0) { /* no block */ + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); + } + else { + genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); + } + } + } + if (val) { + push(); + } +} + +static void +gen_assignment(codegen_scope *s, node *tree, int sp, int val) +{ + int idx; + int type = (intptr_t)tree->car; + + tree = tree->cdr; + switch ((intptr_t)type) { + case NODE_GVAR: + idx = new_sym(s, sym(tree)); + genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); + break; + case NODE_LVAR: + idx = lv_idx(s, sym(tree)); + if (idx > 0) { + if (idx != sp) { + genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); + } + break; + } + else { /* upvar */ + int lv = 0; + codegen_scope *up = s->prev; + + while (up) { + idx = lv_idx(up, sym(tree)); + if (idx > 0) { + genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); + break; + } + lv++; + up = up->prev; + } + } + break; + case NODE_IVAR: + idx = new_sym(s, sym(tree)); + genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); + break; + case NODE_CVAR: + idx = new_sym(s, sym(tree)); + genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); + break; + case NODE_CONST: + idx = new_sym(s, sym(tree)); + genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); + break; + case NODE_COLON2: + idx = new_sym(s, sym(tree->cdr)); + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); + push(); + codegen(s, tree->car, VAL); + pop_n(2); + genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); + break; + + case NODE_CALL: + push(); + gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); + pop(); + if (val) { + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); + } + break; + + case NODE_MASGN: + gen_vmassignment(s, tree->car, sp, val); + break; + + /* splat without assignment */ + case NODE_NIL: + break; + + default: +#ifdef ENABLE_STDIO + printf("unknown lhs %d\n", type); +#endif + break; + } + if (val) push(); +} + +static void +gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) +{ + int n = 0, post = 0; + node *t, *p; + + if (tree->car) { /* pre */ + t = tree->car; + n = 0; + while (t) { + genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n)); + gen_assignment(s, t->car, cursp(), NOVAL); + n++; + t = t->cdr; + } + } + t = tree->cdr; + if (t) { + if (t->cdr) { /* post count */ + p = t->cdr->car; + while (p) { + post++; + p = p->cdr; + } + } + if (val) { + genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + } + else { + pop(); + } + genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); + n = 1; + if (t->car) { /* rest */ + gen_assignment(s, t->car, cursp(), NOVAL); + } + if (t->cdr && t->cdr->car) { + t = t->cdr->car; + while (t) { + gen_assignment(s, t->car, cursp()+n, NOVAL); + t = t->cdr; + n++; + } + } + push(); + } +} + +static void +gen_send_intern(codegen_scope *s) +{ + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); + push(); +} +static void +gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) +{ + if (val) { + int i = 0, j = 0; + + while (tree) { + switch ((intptr_t)tree->car->car) { + case NODE_STR: + if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0)) + break; + /* fall through */ + case NODE_BEGIN: + codegen(s, tree->car, VAL); + ++j; + break; + + case NODE_LITERAL_DELIM: + if (j > 0) { + j = 0; + ++i; + if (sym) + gen_send_intern(s); + } + break; + } + if (j >= 2) { + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + j = 1; + } + tree = tree->cdr; + } + if (j > 0) { + ++i; + if (sym) + gen_send_intern(s); + } + pop_n(i); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + push(); + } + else { + while (tree) { + switch ((intptr_t)tree->car->car) { + case NODE_BEGIN: case NODE_BLOCK: + codegen(s, tree->car, NOVAL); + } + tree = tree->cdr; + } + } +} + +static void +raise_error(codegen_scope *s, const char *msg) +{ + int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); + + genop(s, MKOP_ABx(OP_ERR, 1, idx)); +} + +static double +readint_float(codegen_scope *s, const char *p, int base) +{ + const char *e = p + strlen(p); + double f = 0; + int n; + + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n= 2 && base <= 36); + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n result) { + *overflow = TRUE; + return 0; + } + result *= base; + result -= n; + } + else { + if ((MRB_INT_MAX - n)/base < result) { + *overflow = TRUE; + return 0; + } + result *= base; + result += n; + } + p++; + } + *overflow = FALSE; + return result; +} + +static void +codegen(codegen_scope *s, node *tree, int val) +{ + int nt; + + if (!tree) return; + + if (s->irep && s->filename_index != tree->filename_index) { + s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); + s->debug_start_pos = s->pc; + s->filename_index = tree->filename_index; + s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); + } + + nt = (intptr_t)tree->car; + s->lineno = tree->lineno; + tree = tree->cdr; + switch (nt) { + case NODE_BEGIN: + if (val && !tree) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + while (tree) { + codegen(s, tree->car, tree->cdr ? NOVAL : val); + tree = tree->cdr; + } + break; + + case NODE_RESCUE: + { + int onerr, noexc, exend, pos1, pos2, tmp; + struct loopinfo *lp; + + onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + lp = loop_push(s, LOOP_BEGIN); + lp->pc1 = onerr; + if (tree->car) { + codegen(s, tree->car, val); + if (val) pop(); + } + lp->type = LOOP_RESCUE; + noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + dispatch(s, onerr); + tree = tree->cdr; + exend = 0; + pos1 = 0; + if (tree->car) { + node *n2 = tree->car; + int exc = cursp(); + + genop(s, MKOP_A(OP_RESCUE, exc)); + push(); + while (n2) { + node *n3 = n2->car; + node *n4 = n3->car; + + if (pos1) dispatch(s, pos1); + pos2 = 0; + do { + if (n4) { + codegen(s, n4->car, VAL); + } + else { + genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); + push(); + } + genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); + pop(); + if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + } + tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + pos2 = tmp; + if (n4) { + n4 = n4->cdr; + } + } while (n4); + pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch_linked(s, pos2); + + pop(); + if (n3->cdr->car) { + gen_assignment(s, n3->cdr->car, exc, NOVAL); + } + if (n3->cdr->cdr->car) { + codegen(s, n3->cdr->cdr->car, val); + if (val) pop(); + } + tmp = genop(s, MKOP_sBx(OP_JMP, exend)); + exend = tmp; + n2 = n2->cdr; + push(); + } + if (pos1) { + dispatch(s, pos1); + genop(s, MKOP_A(OP_RAISE, exc)); + } + } + pop(); + tree = tree->cdr; + dispatch(s, noexc); + genop(s, MKOP_A(OP_POPERR, 1)); + if (tree->car) { + codegen(s, tree->car, val); + } + else if (val) { + push(); + } + dispatch_linked(s, exend); + loop_pop(s, NOVAL); + } + break; + + case NODE_ENSURE: + { + int idx; + int epush = s->pc; + + genop(s, MKOP_Bx(OP_EPUSH, 0)); + s->ensure_level++; + codegen(s, tree->car, val); + idx = scope_body(s, tree->cdr, NOVAL); + s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); + s->ensure_level--; + genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); + } + break; + + case NODE_LAMBDA: + { + int idx = lambda_body(s, tree, 1); + + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); + push(); + } + break; + + case NODE_BLOCK: + { + int idx = lambda_body(s, tree, 1); + + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); + push(); + } + break; + + case NODE_IF: + { + int pos1, pos2; + node *e = tree->cdr->cdr->car; + + codegen(s, tree->car, VAL); + pop(); + pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); + + codegen(s, tree->cdr->car, val); + if (val && !(tree->cdr->car)) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + if (e) { + if (val) pop(); + pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch(s, pos1); + codegen(s, e, val); + dispatch(s, pos2); + } + else { + if (val) { + pop(); + pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch(s, pos1); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + dispatch(s, pos2); + push(); + } + else { + dispatch(s, pos1); + } + } + } + break; + + case NODE_AND: + { + int pos; + + codegen(s, tree->car, VAL); + pop(); + pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); + codegen(s, tree->cdr, val); + dispatch(s, pos); + } + break; + + case NODE_OR: + { + int pos; + + codegen(s, tree->car, VAL); + pop(); + pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + codegen(s, tree->cdr, val); + dispatch(s, pos); + } + break; + + case NODE_WHILE: + { + struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + + lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc2 = new_label(s); + codegen(s, tree->cdr, NOVAL); + dispatch(s, lp->pc1); + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); + + loop_pop(s, val); + } + break; + + case NODE_UNTIL: + { + struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + + lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc2 = new_label(s); + codegen(s, tree->cdr, NOVAL); + dispatch(s, lp->pc1); + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); + + loop_pop(s, val); + } + break; + + case NODE_FOR: + for_body(s, tree); + if (val) push(); + break; + + case NODE_CASE: + { + int head = 0; + int pos1, pos2, pos3, tmp; + node *n; + + pos3 = 0; + if (tree->car) { + head = cursp(); + codegen(s, tree->car, VAL); + } + tree = tree->cdr; + while (tree) { + n = tree->car->car; + pos1 = pos2 = 0; + while (n) { + codegen(s, n->car, VAL); + if (head) { + genop(s, MKOP_AB(OP_MOVE, cursp(), head)); + pop(); + if ((intptr_t)n->car->car == NODE_SPLAT) { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + } + } + else { + pop(); + } + tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + pos2 = tmp; + n = n->cdr; + } + if (tree->car->car) { + pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch_linked(s, pos2); + } + codegen(s, tree->car->cdr, val); + if (val) pop(); + tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); + pos3 = tmp; + if (pos1) dispatch(s, pos1); + tree = tree->cdr; + } + if (val) { + int pos = cursp(); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + if (pos3) dispatch_linked(s, pos3); + if (head) pop(); + genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + push(); + } + else { + if (pos3) { + dispatch_linked(s, pos3); + } + if (head) { + pop(); + } + } + } + break; + + case NODE_SCOPE: + scope_body(s, tree, NOVAL); + break; + + case NODE_FCALL: + case NODE_CALL: + gen_call(s, tree, 0, 0, val); + break; + + case NODE_DOT2: + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (val) { + pop(); pop(); + genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); + push(); + } + break; + + case NODE_DOT3: + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (val) { + pop(); pop(); + genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); + push(); + } + break; + + case NODE_COLON2: + { + int sym = new_sym(s, sym(tree->cdr)); + + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + if (val) push(); + } + break; + + case NODE_COLON3: + { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + if (val) push(); + } + break; + + case NODE_ARRAY: + { + int n; + + n = gen_values(s, tree, val); + if (n >= 0) { + if (val) { + pop_n(n); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + push(); + } + } + else if (val) { + push(); + } + } + break; + + case NODE_HASH: + { + int len = 0; + mrb_bool update = FALSE; + + while (tree) { + codegen(s, tree->car->car, val); + codegen(s, tree->car->cdr, val); + len++; + tree = tree->cdr; + if (val && len == 126) { + pop_n(len*2); + genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } + push(); + update = TRUE; + len = 0; + } + } + if (val) { + pop_n(len*2); + genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } + push(); + } + } + break; + + case NODE_SPLAT: + codegen(s, tree, VAL); + break; + + case NODE_ASGN: + codegen(s, tree->cdr, VAL); + pop(); + gen_assignment(s, tree->car, cursp(), val); + break; + + case NODE_MASGN: + { + int len = 0, n = 0, post = 0; + node *t = tree->cdr, *p; + int rhs = cursp(); + + if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) { + /* fixed rhs */ + t = t->cdr; + while (t) { + codegen(s, t->car, VAL); + len++; + t = t->cdr; + } + tree = tree->car; + if (tree->car) { /* pre */ + t = tree->car; + n = 0; + while (t) { + gen_assignment(s, t->car, rhs+n, NOVAL); + n++; + t = t->cdr; + } + } + t = tree->cdr; + if (t) { + if (t->cdr) { /* post count */ + p = t->cdr->car; + while (p) { + post++; + p = p->cdr; + } + } + if (t->car) { /* rest (len - pre - post) */ + int rn; + + if (len < post + n) { + rn = 0; + } + else { + rn = len - post - n; + } + genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); + gen_assignment(s, t->car, cursp(), NOVAL); + n += rn; + } + if (t->cdr && t->cdr->car) { + t = t->cdr->car; + while (ncar, rhs+n, NOVAL); + t = t->cdr; + n++; + } + } + } + pop_n(len); + if (val) { + genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); + push(); + } + } + else { + /* variable rhs */ + codegen(s, t, VAL); + gen_vmassignment(s, tree->car, rhs, val); + if (!val) { + pop(); + } + } + } + break; + + case NODE_OP_ASGN: + { + mrb_sym sym = sym(tree->cdr->car); + mrb_int len; + const char *name = mrb_sym2name_len(s->mrb, sym, &len); + int idx; + + codegen(s, tree->car, VAL); + if (len == 2 && + ((name[0] == '|' && name[1] == '|') || + (name[0] == '&' && name[1] == '&'))) { + int pos; + + pop(); + pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL); + codegen(s, tree->cdr->cdr->car, VAL); + pop(); + gen_assignment(s, tree->car, cursp(), val); + dispatch(s, pos); + break; + } + codegen(s, tree->cdr->cdr->car, VAL); + push(); pop(); + pop(); pop(); + + idx = new_msym(s, sym); + if (len == 1 && name[0] == '+') { + genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); + } + else if (len == 1 && name[0] == '-') { + genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); + } + else if (len == 1 && name[0] == '*') { + genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '/') { + genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '<') { + genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); + } + else if (len == 2 && name[0] == '<' && name[1] == '=') { + genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '>') { + genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); + } + else if (len == 2 && name[0] == '>' && name[1] == '=') { + genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); + } + } + gen_assignment(s, tree->car, cursp(), val); + break; + + case NODE_SUPER: + { + int n = 0, noop = 0, sendv = 0; + + push(); /* room for receiver */ + if (tree) { + node *args = tree->car; + if (args) { + n = gen_values(s, args, VAL); + if (n < 0) { + n = noop = sendv = 1; + push(); + } + } + } + if (tree && tree->cdr) { + codegen(s, tree->cdr, VAL); + pop(); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); pop(); + } + pop_n(n+1); + if (sendv) n = CALL_MAXARGS; + genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); + if (val) push(); + } + break; + + case NODE_ZSUPER: + { + codegen_scope *s2 = s; + int lv = 0, ainfo = 0; + + push(); /* room for receiver */ + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2) ainfo = s2->ainfo; + genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); + push(); push(); pop(); /* ARGARY pushes two values */ + if (tree && tree->cdr) { + codegen(s, tree->cdr, VAL); + pop(); + } + pop(); pop(); + genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); + if (val) push(); + } + break; + + case NODE_RETURN: + if (tree) { + codegen(s, tree, VAL); + pop(); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + if (s->loop) { + genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); + } + else { + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + if (val) push(); + break; + + case NODE_YIELD: + { + codegen_scope *s2 = s; + int lv = 0, ainfo = 0; + int n = 0, sendv = 0; + + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2) ainfo = s2->ainfo; + genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); + push(); + if (tree) { + n = gen_values(s, tree, VAL); + if (n < 0) { + n = sendv = 1; + push(); + } + } + pop_n(n+1); + if (sendv) n = CALL_MAXARGS; + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); + if (val) push(); + } + break; + + case NODE_BREAK: + loop_break(s, tree); + if (val) push(); + break; + + case NODE_NEXT: + if (!s->loop) { + raise_error(s, "unexpected next"); + } + else if (s->loop->type == LOOP_NORMAL) { + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + codegen(s, tree, NOVAL); + genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); + } + else { + if (tree) { + codegen(s, tree, VAL); + pop(); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + if (val) push(); + break; + + case NODE_REDO: + if (!s->loop) { + raise_error(s, "unexpected redo"); + } + else { + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); + } + break; + + case NODE_RETRY: + { + const char *msg = "unexpected retry"; + + if (!s->loop) { + raise_error(s, msg); + } + else { + struct loopinfo *lp = s->loop; + int n = 0; + + while (lp && lp->type != LOOP_RESCUE) { + if (lp->type == LOOP_BEGIN) { + n++; + } + lp = lp->prev; + } + if (!lp) { + raise_error(s, msg); + } + else { + if (n > 0) { + while (n--) { + genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); + } + } + if (s->ensure_level > lp->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); + } + genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); + } + } + } + break; + + case NODE_LVAR: + if (val) { + int idx = lv_idx(s, sym(tree)); + + if (idx > 0) { + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); + } + else { + int lv = 0; + codegen_scope *up = s->prev; + + while (up) { + idx = lv_idx(up, sym(tree)); + if (idx > 0) { + genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv)); + break; + } + lv++; + up = up->prev; + } + } + push(); + } + break; + + case NODE_GVAR: + if (val) { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_IVAR: + if (val) { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); + push(); + } + break; + + case NODE_CVAR: + if (val) { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); + push(); + } + break; + + case NODE_CONST: + { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); + push(); + } + break; + + case NODE_DEFINED: + codegen(s, tree, VAL); + break; + + case NODE_BACK_REF: + if (val) { + char buf[2] = { '$' }; + mrb_value str; + int sym; + + buf[1] = (char)(intptr_t)tree; + str = mrb_str_new(s->mrb, buf, 2); + sym = new_sym(s, mrb_intern_str(s->mrb, str)); + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_NTH_REF: + if (val) { + int sym; + mrb_state *mrb = s->mrb; + mrb_value fix = mrb_fixnum_value((intptr_t)tree); + mrb_value str = mrb_str_buf_new(mrb, 4); + + mrb_str_cat_lit(mrb, str, "$"); + mrb_str_cat_str(mrb, str, mrb_fixnum_to_str(mrb, fix, 10)); + sym = new_sym(s, mrb_intern_str(mrb, str)); + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_ARG: + /* should not happen */ + break; + + case NODE_BLOCK_ARG: + codegen(s, tree, VAL); + break; + + case NODE_INT: + if (val) { + char *p = (char*)tree->car; + int base = (intptr_t)tree->cdr->car; + mrb_int i; + mrb_code co; + mrb_bool overflow; + + i = readint_mrb_int(s, p, base, FALSE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); + int off = new_lit(s, mrb_float_value(s->mrb, f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + } + else { + if (i < MAXARG_sBx && i > -MAXARG_sBx) { + co = MKOP_AsBx(OP_LOADI, cursp(), i); + } + else { + int off = new_lit(s, mrb_fixnum_value(i)); + co = MKOP_ABx(OP_LOADL, cursp(), off); + } + genop(s, co); + } + push(); + } + break; + + case NODE_FLOAT: + if (val) { + char *p = (char*)tree; + mrb_float f = str_to_mrb_float(p); + int off = new_lit(s, mrb_float_value(s->mrb, f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + push(); + } + break; + + case NODE_NEGATE: + { + nt = (intptr_t)tree->car; + tree = tree->cdr; + switch (nt) { + case NODE_FLOAT: + { + char *p = (char*)tree; + mrb_float f = str_to_mrb_float(p); + int off = new_lit(s, mrb_float_value(s->mrb, -f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + push(); + } + break; + + case NODE_INT: + { + char *p = (char*)tree->car; + int base = (intptr_t)tree->cdr->car; + mrb_int i; + mrb_code co; + mrb_bool overflow; + + i = readint_mrb_int(s, p, base, TRUE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); + int off = new_lit(s, mrb_float_value(s->mrb, -f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + } + else { + if (i < MAXARG_sBx && i > -MAXARG_sBx) { + co = MKOP_AsBx(OP_LOADI, cursp(), i); + } + else { + int off = new_lit(s, mrb_fixnum_value(i)); + co = MKOP_ABx(OP_LOADL, cursp(), off); + } + genop(s, co); + } + push(); + } + break; + + default: + { + int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); + + genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); + push(); + codegen(s, tree, VAL); + pop(); pop(); + genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + } + break; + } + } + break; + + case NODE_STR: + if (val) { + char *p = (char*)tree->car; + size_t len = (intptr_t)tree->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int off = new_lit(s, mrb_str_new(s->mrb, p, len)); + + mrb_gc_arena_restore(s->mrb, ai); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + } + break; + + case NODE_HEREDOC: + tree = ((struct mrb_parser_heredoc_info *)tree)->doc; + /* fall through */ + case NODE_DSTR: + if (val) { + node *n = tree; + + if (!n) break; + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + } + else { + node *n = tree; + + while (n) { + if ((intptr_t)n->car->car != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } + break; + + case NODE_WORDS: + gen_literal_array(s, tree, FALSE, val); + break; + + case NODE_SYMBOLS: + gen_literal_array(s, tree, TRUE, val); + break; + + case NODE_DXSTR: + { + node *n; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); + + if (val == NOVAL) { push(); } + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + codegen(s, tree->car, VAL); + n = tree->cdr; + while (n) { + if ((intptr_t)n->car->car == NODE_XSTR) { + n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; + mrb_assert(!n->cdr); /* must be the end */ + } + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + pop(); + pop(); + sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + if (val == NOVAL) { pop(); } + else { push(); } + mrb_gc_arena_restore(s->mrb, ai); + } + break; + + case NODE_XSTR: + { + char *p = (char*)tree->car; + size_t len = (intptr_t)tree->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); + int off = new_lit(s, mrb_str_new(s->mrb, p, len)); + + if (val == NOVAL) { push(); } + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + pop(); + sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + if (val == NOVAL) { pop(); } + else { push(); } + mrb_gc_arena_restore(s->mrb, ai); + } + break; + + case NODE_REGX: + if (val) { + char *p1 = (char*)tree->car; + char *p2 = (char*)tree->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); + int argc = 1; + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + if (p2) { + push(); + off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + argc++; + pop(); + } + pop(); + sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + mrb_gc_arena_restore(s->mrb, ai); + push(); + } + break; + + case NODE_DREGX: + if (val) { + node *n = tree->car; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int argc = 1; + int off; + char *p; + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + n = tree->cdr->cdr; + if (n->car) { + p = (char*)n->car; + off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); + codegen(s, tree->car, VAL); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + } + if (n->cdr) { + char *p2 = (char*)n->cdr; + + push(); + off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + argc++; + pop(); + } + pop(); + sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + mrb_gc_arena_restore(s->mrb, ai); + push(); + } + else { + node *n = tree->car; + + while (n) { + if ((intptr_t)n->car->car != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } + break; + + case NODE_SYM: + if (val) { + int sym = new_sym(s, sym(tree)); + + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + break; + + case NODE_DSYM: + codegen(s, tree, val); + if (val) { + gen_send_intern(s); + } + break; + + case NODE_SELF: + if (val) { + genop(s, MKOP_A(OP_LOADSELF, cursp())); + push(); + } + break; + + case NODE_NIL: + if (val) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + break; + + case NODE_TRUE: + if (val) { + genop(s, MKOP_A(OP_LOADT, cursp())); + push(); + } + break; + + case NODE_FALSE: + if (val) { + genop(s, MKOP_A(OP_LOADF, cursp())); + push(); + } + break; + + case NODE_ALIAS: + { + int a = new_msym(s, sym(tree->car)); + int b = new_msym(s, sym(tree->cdr)); + int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); + push(); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); + push(); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + pop_n(3); + genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); + if (val) { + push(); + } + } + break; + + case NODE_UNDEF: + { + int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); + int num = 0; + node *t = tree; + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + while (t) { + int symbol = new_msym(s, sym(t->car)); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); + push(); + t = t->cdr; + num++; + } + pop_n(num + 1); + genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); + if (val) { + push(); + } + } + break; + + case NODE_CLASS: + { + int idx; + + if (tree->car->car == (node*)0) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + else if (tree->car->car == (node*)1) { + genop(s, MKOP_A(OP_OCLASS, cursp())); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + if (tree->cdr->car) { + codegen(s, tree->cdr->car, VAL); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + pop(); pop(); + idx = new_msym(s, sym(tree->car->cdr)); + genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); + idx = scope_body(s, tree->cdr->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_MODULE: + { + int idx; + + if (tree->car->car == (node*)0) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + else if (tree->car->car == (node*)1) { + genop(s, MKOP_A(OP_OCLASS, cursp())); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + pop(); + idx = new_msym(s, sym(tree->car->cdr)); + genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); + idx = scope_body(s, tree->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_SCLASS: + { + int idx; + + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + idx = scope_body(s, tree->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_DEF: + { + int sym = new_msym(s, sym(tree->car)); + int idx = lambda_body(s, tree->cdr, 0); + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + push(); pop(); + pop(); + genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + if (val) { + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + } + break; + + case NODE_SDEF: + { + node *recv = tree->car; + int sym = new_msym(s, sym(tree->cdr->car)); + int idx = lambda_body(s, tree->cdr->cdr, 0); + + codegen(s, recv, VAL); + pop(); + genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + push(); + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + pop(); + genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + if (val) { + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + } + break; + + case NODE_POSTEXE: + codegen(s, tree, NOVAL); + break; + + default: + break; + } +} + +static void +scope_add_irep(codegen_scope *s, mrb_irep *irep) +{ + if (s->irep == NULL) { + s->irep = irep; + return; + } + if (s->irep->rlen == s->rcapa) { + s->rcapa *= 2; + s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa); + } + s->irep->reps[s->irep->rlen] = irep; + s->irep->rlen++; +} + +static codegen_scope* +scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) +{ + static const codegen_scope codegen_scope_zero = { 0 }; + mrb_pool *pool = mrb_pool_open(mrb); + codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); + + if (!p) return NULL; + *p = codegen_scope_zero; + p->mrb = mrb; + p->mpool = pool; + if (!prev) return p; + p->prev = prev; + p->ainfo = -1; + p->mscope = 0; + + p->irep = mrb_add_irep(mrb); + scope_add_irep(prev, p->irep); + + p->rcapa = 8; + p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa); + + p->icapa = 1024; + p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa); + p->irep->iseq = p->iseq; + + p->pcapa = 32; + p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); + p->irep->plen = 0; + + p->scapa = 256; + p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); + p->irep->slen = 0; + + p->lv = lv; + p->sp += node_len(lv)+1; /* add self */ + p->nlocals = p->sp; + if (lv) { + node *n = lv; + size_t i = 0; + + p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1)); + for (i=0, n=lv; n; i++,n=n->cdr) { + p->irep->lv[i].name = lv_name(n); + if (lv_name(n)) { + p->irep->lv[i].r = lv_idx(p, lv_name(n)); + } + else { + p->irep->lv[i].r = 0; + } + } + mrb_assert(i + 1 == p->nlocals); + } + p->ai = mrb_gc_arena_save(mrb); + + p->filename = prev->filename; + if (p->filename) { + p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa); + } + p->lineno = prev->lineno; + + /* debug setting */ + p->debug_start_pos = 0; + if (p->filename) { + mrb_debug_info_alloc(mrb, p->irep); + p->irep->filename = p->filename; + p->irep->lines = p->lines; + } + else { + p->irep->debug_info = NULL; + } + p->parser = prev->parser; + p->filename_index = prev->filename_index; + + return p; +} + +static void +scope_finish(codegen_scope *s) +{ + mrb_state *mrb = s->mrb; + mrb_irep *irep = s->irep; + size_t fname_len; + char *fname; + + irep->flags = 0; + if (s->iseq) { + irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); + irep->ilen = s->pc; + if (s->lines) { + irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); + } + else { + irep->lines = 0; + } + } + irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); + irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); + irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); + if (s->filename) { + s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc); + + fname_len = strlen(s->filename); + fname = (char*)codegen_malloc(s, fname_len + 1); + memcpy(fname, s->filename, fname_len); + fname[fname_len] = '\0'; + irep->filename = fname; + } + + irep->nlocals = s->nlocals; + irep->nregs = s->nregs; + + mrb_gc_arena_restore(mrb, s->ai); + mrb_pool_close(s->mpool); +} + +static struct loopinfo* +loop_push(codegen_scope *s, enum looptype t) +{ + struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); + + p->type = t; + p->pc1 = p->pc2 = p->pc3 = 0; + p->prev = s->loop; + p->ensure_level = s->ensure_level; + p->acc = cursp(); + s->loop = p; + + return p; +} + +static void +loop_break(codegen_scope *s, node *tree) +{ + if (!s->loop) { + codegen(s, tree, NOVAL); + raise_error(s, "unexpected break"); + } + else { + struct loopinfo *loop; + + if (tree) { + codegen(s, tree, VAL); + pop(); + } + + loop = s->loop; + while (loop->type == LOOP_BEGIN) { + genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); + loop = loop->prev; + } + while (loop->type == LOOP_RESCUE) { + loop = loop->prev; + } + if (loop->type == LOOP_NORMAL) { + int tmp; + + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + if (tree) { + genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); + } + tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); + loop->pc3 = tmp; + } + else { + genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); + } + } +} + +static void +loop_pop(codegen_scope *s, int val) +{ + if (val) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + dispatch_linked(s, s->loop->pc3); + s->loop = s->loop->prev; + if (val) push(); +} + +MRB_API struct RProc* +mrb_generate_code(mrb_state *mrb, parser_state *p) +{ + codegen_scope *scope = scope_new(mrb, 0, 0); + struct RProc *proc; + + if (!scope) { + return NULL; + } + scope->mrb = mrb; + scope->parser = p; + scope->filename = p->filename; + scope->filename_index = p->current_filename_index; + + MRB_TRY(&scope->jmp) { + /* prepare irep */ + codegen(scope, p->tree, NOVAL); + proc = mrb_proc_new(mrb, scope->irep); + mrb_irep_decref(mrb, scope->irep); + mrb_pool_close(scope->mpool); + return proc; + } + MRB_CATCH(&scope->jmp) { + if (scope->filename == scope->irep->filename) { + scope->irep->filename = NULL; + } + mrb_irep_decref(mrb, scope->irep); + mrb_pool_close(scope->mpool); + return NULL; + } + MRB_END_EXC(&scope->jmp); +} diff --git a/mrbgems/mruby-compiler/core/keywords b/mrbgems/mruby-compiler/core/keywords new file mode 100644 index 000000000..9cb86608c --- /dev/null +++ b/mrbgems/mruby-compiler/core/keywords @@ -0,0 +1,50 @@ +%{ +struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; +const struct kwtable *mrb_reserved_word(const char *, unsigned int); +static const struct kwtable *reserved_word(const char *, unsigned int); +#define mrb_reserved_word(str, len) reserved_word(str, len) +%} + +struct kwtable; +%% +__ENCODING__, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END +__FILE__, {keyword__FILE__, keyword__FILE__}, EXPR_END +__LINE__, {keyword__LINE__, keyword__LINE__}, EXPR_END +BEGIN, {keyword_BEGIN, keyword_BEGIN}, EXPR_END +END, {keyword_END, keyword_END}, EXPR_END +alias, {keyword_alias, keyword_alias}, EXPR_FNAME +and, {keyword_and, keyword_and}, EXPR_VALUE +begin, {keyword_begin, keyword_begin}, EXPR_BEG +break, {keyword_break, keyword_break}, EXPR_MID +case, {keyword_case, keyword_case}, EXPR_VALUE +class, {keyword_class, keyword_class}, EXPR_CLASS +def, {keyword_def, keyword_def}, EXPR_FNAME +do, {keyword_do, keyword_do}, EXPR_BEG +else, {keyword_else, keyword_else}, EXPR_BEG +elsif, {keyword_elsif, keyword_elsif}, EXPR_VALUE +end, {keyword_end, keyword_end}, EXPR_END +ensure, {keyword_ensure, keyword_ensure}, EXPR_BEG +false, {keyword_false, keyword_false}, EXPR_END +for, {keyword_for, keyword_for}, EXPR_VALUE +if, {keyword_if, modifier_if}, EXPR_VALUE +in, {keyword_in, keyword_in}, EXPR_VALUE +module, {keyword_module, keyword_module}, EXPR_VALUE +next, {keyword_next, keyword_next}, EXPR_MID +nil, {keyword_nil, keyword_nil}, EXPR_END +not, {keyword_not, keyword_not}, EXPR_ARG +or, {keyword_or, keyword_or}, EXPR_VALUE +redo, {keyword_redo, keyword_redo}, EXPR_END +rescue, {keyword_rescue, modifier_rescue}, EXPR_MID +retry, {keyword_retry, keyword_retry}, EXPR_END +return, {keyword_return, keyword_return}, EXPR_MID +self, {keyword_self, keyword_self}, EXPR_END +super, {keyword_super, keyword_super}, EXPR_ARG +then, {keyword_then, keyword_then}, EXPR_BEG +true, {keyword_true, keyword_true}, EXPR_END +undef, {keyword_undef, keyword_undef}, EXPR_FNAME +unless, {keyword_unless, modifier_unless}, EXPR_VALUE +until, {keyword_until, modifier_until}, EXPR_VALUE +when, {keyword_when, keyword_when}, EXPR_VALUE +while, {keyword_while, modifier_while}, EXPR_VALUE +yield, {keyword_yield, keyword_yield}, EXPR_ARG +%% diff --git a/mrbgems/mruby-compiler/core/lex.def b/mrbgems/mruby-compiler/core/lex.def new file mode 100644 index 000000000..ea456a843 --- /dev/null +++ b/mrbgems/mruby-compiler/core/lex.def @@ -0,0 +1,212 @@ +/* ANSI-C code produced by gperf version 3.0.3 */ +/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 1 "src/keywords" + +struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; +const struct kwtable *mrb_reserved_word(const char *, unsigned int); +static const struct kwtable *reserved_word(const char *, unsigned int); +#define mrb_reserved_word(str, len) reserved_word(str, len) +#line 8 "src/keywords" +struct kwtable; + +#define TOTAL_KEYWORDS 40 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 50 +/* maximum key range = 43, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (register const char *str, register unsigned int len) +{ + static const unsigned char asso_values[] = + { + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 14, 51, 16, 8, + 11, 13, 51, 51, 51, 51, 10, 51, 13, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 11, 51, 13, 1, 26, + 4, 1, 8, 28, 51, 23, 51, 1, 1, 27, + 5, 19, 21, 51, 8, 3, 3, 11, 51, 21, + 24, 16, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct kwtable * +mrb_reserved_word (register const char *str, register unsigned int len) +{ + static const struct kwtable wordlist[] = + { + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 18 "src/keywords" + {"break", {keyword_break, keyword_break}, EXPR_MID}, +#line 23 "src/keywords" + {"else", {keyword_else, keyword_else}, EXPR_BEG}, +#line 33 "src/keywords" + {"nil", {keyword_nil, keyword_nil}, EXPR_END}, +#line 26 "src/keywords" + {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, +#line 25 "src/keywords" + {"end", {keyword_end, keyword_end}, EXPR_END}, +#line 42 "src/keywords" + {"then", {keyword_then, keyword_then}, EXPR_BEG}, +#line 34 "src/keywords" + {"not", {keyword_not, keyword_not}, EXPR_ARG}, +#line 27 "src/keywords" + {"false", {keyword_false, keyword_false}, EXPR_END}, +#line 40 "src/keywords" + {"self", {keyword_self, keyword_self}, EXPR_END}, +#line 24 "src/keywords" + {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, +#line 37 "src/keywords" + {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, +#line 43 "src/keywords" + {"true", {keyword_true, keyword_true}, EXPR_END}, +#line 46 "src/keywords" + {"until", {keyword_until, modifier_until}, EXPR_VALUE}, +#line 45 "src/keywords" + {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, +#line 39 "src/keywords" + {"return", {keyword_return, keyword_return}, EXPR_MID}, +#line 21 "src/keywords" + {"def", {keyword_def, keyword_def}, EXPR_FNAME}, +#line 16 "src/keywords" + {"and", {keyword_and, keyword_and}, EXPR_VALUE}, +#line 22 "src/keywords" + {"do", {keyword_do, keyword_do}, EXPR_BEG}, +#line 49 "src/keywords" + {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, +#line 28 "src/keywords" + {"for", {keyword_for, keyword_for}, EXPR_VALUE}, +#line 44 "src/keywords" + {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, +#line 35 "src/keywords" + {"or", {keyword_or, keyword_or}, EXPR_VALUE}, +#line 30 "src/keywords" + {"in", {keyword_in, keyword_in}, EXPR_VALUE}, +#line 47 "src/keywords" + {"when", {keyword_when, keyword_when}, EXPR_VALUE}, +#line 38 "src/keywords" + {"retry", {keyword_retry, keyword_retry}, EXPR_END}, +#line 29 "src/keywords" + {"if", {keyword_if, modifier_if}, EXPR_VALUE}, +#line 19 "src/keywords" + {"case", {keyword_case, keyword_case}, EXPR_VALUE}, +#line 36 "src/keywords" + {"redo", {keyword_redo, keyword_redo}, EXPR_END}, +#line 32 "src/keywords" + {"next", {keyword_next, keyword_next}, EXPR_MID}, +#line 41 "src/keywords" + {"super", {keyword_super, keyword_super}, EXPR_ARG}, +#line 31 "src/keywords" + {"module", {keyword_module, keyword_module}, EXPR_VALUE}, +#line 17 "src/keywords" + {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, +#line 12 "src/keywords" + {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, +#line 11 "src/keywords" + {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, +#line 10 "src/keywords" + {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, +#line 14 "src/keywords" + {"END", {keyword_END, keyword_END}, EXPR_END}, +#line 15 "src/keywords" + {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, +#line 13 "src/keywords" + {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, + {""}, +#line 20 "src/keywords" + {"class", {keyword_class, keyword_class}, EXPR_CLASS}, + {""}, {""}, +#line 48 "src/keywords" + {"while", {keyword_while, modifier_while}, EXPR_VALUE} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register const char *s = wordlist[key].name; + + if (*str == *s && !strcmp (str + 1, s + 1)) + return &wordlist[key]; + } + } + return 0; +} +#line 50 "src/keywords" + diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h new file mode 100644 index 000000000..532a8323a --- /dev/null +++ b/mrbgems/mruby-compiler/core/node.h @@ -0,0 +1,117 @@ +/* +** node.h - nodes of abstract syntax tree +** +** See Copyright Notice in mruby.h +*/ + +#ifndef NODE_H +#define NODE_H + +enum node_type { + NODE_METHOD, + NODE_FBODY, + NODE_CFUNC, + NODE_SCOPE, + NODE_BLOCK, + NODE_IF, + NODE_CASE, + NODE_WHEN, + NODE_OPT_N, + NODE_WHILE, + NODE_UNTIL, + NODE_ITER, + NODE_FOR, + NODE_BREAK, + NODE_NEXT, + NODE_REDO, + NODE_RETRY, + NODE_BEGIN, + NODE_RESCUE, + NODE_ENSURE, + NODE_AND, + NODE_OR, + NODE_NOT, + NODE_MASGN, + NODE_ASGN, + NODE_CDECL, + NODE_CVASGN, + NODE_CVDECL, + NODE_OP_ASGN, + NODE_CALL, + NODE_FCALL, + NODE_VCALL, + NODE_SUPER, + NODE_ZSUPER, + NODE_ARRAY, + NODE_ZARRAY, + NODE_HASH, + NODE_RETURN, + NODE_YIELD, + NODE_LVAR, + NODE_DVAR, + NODE_GVAR, + NODE_IVAR, + NODE_CONST, + NODE_CVAR, + NODE_NTH_REF, + NODE_BACK_REF, + NODE_MATCH, + NODE_MATCH2, + NODE_MATCH3, + NODE_INT, + NODE_FLOAT, + NODE_NEGATE, + NODE_LAMBDA, + NODE_SYM, + NODE_STR, + NODE_DSTR, + NODE_XSTR, + NODE_DXSTR, + NODE_REGX, + NODE_DREGX, + NODE_DREGX_ONCE, + NODE_LIST, + NODE_ARG, + NODE_ARGSCAT, + NODE_ARGSPUSH, + NODE_SPLAT, + NODE_TO_ARY, + NODE_SVALUE, + NODE_BLOCK_ARG, + NODE_DEF, + NODE_SDEF, + NODE_ALIAS, + NODE_UNDEF, + NODE_CLASS, + NODE_MODULE, + NODE_SCLASS, + NODE_COLON2, + NODE_COLON3, + NODE_CREF, + NODE_DOT2, + NODE_DOT3, + NODE_FLIP2, + NODE_FLIP3, + NODE_ATTRSET, + NODE_SELF, + NODE_NIL, + NODE_TRUE, + NODE_FALSE, + NODE_DEFINED, + NODE_NEWLINE, + NODE_POSTEXE, + NODE_ALLOCA, + NODE_DMETHOD, + NODE_BMETHOD, + NODE_MEMO, + NODE_IFUNC, + NODE_DSYM, + NODE_ATTRASGN, + NODE_HEREDOC, + NODE_LITERAL_DELIM, + NODE_WORDS, + NODE_SYMBOLS, + NODE_LAST +}; + +#endif /* NODE_H */ diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y new file mode 100644 index 000000000..5b17649a9 --- /dev/null +++ b/mrbgems/mruby-compiler/core/parse.y @@ -0,0 +1,6420 @@ +/* +** parse.y - mruby parser +** +** See Copyright Notice in mruby.h +*/ + +%{ +#undef PARSER_DEBUG +#ifdef PARSER_DEBUG +# define YYDEBUG 1 +#endif +#define YYERROR_VERBOSE 1 +/* + * Force yacc to use our memory management. This is a little evil because + * the macros assume that "parser_state *p" is in scope + */ +#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) +#define YYFREE(o) mrb_free(p->mrb, (o)) +#define YYSTACK_USE_ALLOCA 0 + +#include +#include +#include +#include +#include "mruby.h" +#include "mruby/compile.h" +#include "mruby/proc.h" +#include "mruby/error.h" +#include "node.h" +#include "mruby/throw.h" + +#define YYLEX_PARAM p + +typedef mrb_ast_node node; +typedef struct mrb_parser_state parser_state; +typedef struct mrb_parser_heredoc_info parser_heredoc_info; + +static int yyparse(parser_state *p); +static int yylex(void *lval, parser_state *p); +static void yyerror(parser_state *p, const char *s); +static void yywarn(parser_state *p, const char *s); +static void yywarning(parser_state *p, const char *s); +static void backref_error(parser_state *p, node *n); +static void tokadd(parser_state *p, int32_t c); + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +typedef unsigned int stack_type; + +#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1)) +#define BITSTACK_POP(stack) ((stack) = (stack) >> 1) +#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1)) +#define BITSTACK_SET_P(stack) ((stack)&1) + +#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n)) +#define COND_POP() BITSTACK_POP(p->cond_stack) +#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack) +#define COND_P() BITSTACK_SET_P(p->cond_stack) + +#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n)) +#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack) +#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack) +#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) + +#define SET_LINENO(c,n) ((c)->lineno = (n)) +#define NODE_LINENO(c,n) do {\ + if (n) {\ + (c)->filename_index = (n)->filename_index;\ + (c)->lineno = (n)->lineno;\ + }\ +} while (0) + +#define sym(x) ((mrb_sym)(intptr_t)(x)) +#define nsym(x) ((node*)(intptr_t)(x)) + +static inline mrb_sym +intern_cstr_gen(parser_state *p, const char *s) +{ + return mrb_intern_cstr(p->mrb, s); +} +#define intern_cstr(s) intern_cstr_gen(p,(s)) + +static inline mrb_sym +intern_gen(parser_state *p, const char *s, size_t len) +{ + return mrb_intern(p->mrb, s, len); +} +#define intern(s,len) intern_gen(p,(s),(len)) + +static inline mrb_sym +intern_gen_c(parser_state *p, const char c) +{ + return mrb_intern(p->mrb, &c, 1); +} +#define intern_c(c) intern_gen_c(p,(c)) + +static void +cons_free_gen(parser_state *p, node *cons) +{ + cons->cdr = p->cells; + p->cells = cons; +} +#define cons_free(c) cons_free_gen(p, (c)) + +static void* +parser_palloc(parser_state *p, size_t size) +{ + void *m = mrb_pool_alloc(p->pool, size); + + if (!m) { + MRB_THROW(p->jmp); + } + return m; +} + +static node* +cons_gen(parser_state *p, node *car, node *cdr) +{ + node *c; + + if (p->cells) { + c = p->cells; + p->cells = p->cells->cdr; + } + else { + c = (node *)parser_palloc(p, sizeof(mrb_ast_node)); + } + + c->car = car; + c->cdr = cdr; + c->lineno = p->lineno; + c->filename_index = p->current_filename_index; + return c; +} +#define cons(a,b) cons_gen(p,(a),(b)) + +static node* +list1_gen(parser_state *p, node *a) +{ + return cons(a, 0); +} +#define list1(a) list1_gen(p, (a)) + +static node* +list2_gen(parser_state *p, node *a, node *b) +{ + return cons(a, cons(b,0)); +} +#define list2(a,b) list2_gen(p, (a),(b)) + +static node* +list3_gen(parser_state *p, node *a, node *b, node *c) +{ + return cons(a, cons(b, cons(c,0))); +} +#define list3(a,b,c) list3_gen(p, (a),(b),(c)) + +static node* +list4_gen(parser_state *p, node *a, node *b, node *c, node *d) +{ + return cons(a, cons(b, cons(c, cons(d, 0)))); +} +#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d)) + +static node* +list5_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e) +{ + return cons(a, cons(b, cons(c, cons(d, cons(e, 0))))); +} +#define list5(a,b,c,d,e) list5_gen(p, (a),(b),(c),(d),(e)) + +static node* +list6_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e, node *f) +{ + return cons(a, cons(b, cons(c, cons(d, cons(e, cons(f, 0)))))); +} +#define list6(a,b,c,d,e,f) list6_gen(p, (a),(b),(c),(d),(e),(f)) + +static node* +append_gen(parser_state *p, node *a, node *b) +{ + node *c = a; + + if (!a) return b; + while (c->cdr) { + c = c->cdr; + } + if (b) { + c->cdr = b; + } + return a; +} +#define append(a,b) append_gen(p,(a),(b)) +#define push(a,b) append_gen(p,(a),list1(b)) + +static char* +parser_strndup(parser_state *p, const char *s, size_t len) +{ + char *b = (char *)parser_palloc(p, len+1); + + memcpy(b, s, len); + b[len] = '\0'; + return b; +} +#undef strndup +#define strndup(s,len) parser_strndup(p, s, len) + +static char* +parser_strdup(parser_state *p, const char *s) +{ + return parser_strndup(p, s, strlen(s)); +} +#undef strdup +#define strdup(s) parser_strdup(p, s) + +/* xxx ----------------------------- */ + +static node* +local_switch(parser_state *p) +{ + node *prev = p->locals; + + p->locals = cons(0, 0); + return prev; +} + +static void +local_resume(parser_state *p, node *prev) +{ + p->locals = prev; +} + +static void +local_nest(parser_state *p) +{ + p->locals = cons(0, p->locals); +} + +static void +local_unnest(parser_state *p) +{ + if (p->locals) { + p->locals = p->locals->cdr; + } +} + +static mrb_bool +local_var_p(parser_state *p, mrb_sym sym) +{ + node *l = p->locals; + + while (l) { + node *n = l->car; + while (n) { + if (sym(n->car) == sym) return TRUE; + n = n->cdr; + } + l = l->cdr; + } + return FALSE; +} + +static void +local_add_f(parser_state *p, mrb_sym sym) +{ + if (p->locals) { + p->locals->car = push(p->locals->car, nsym(sym)); + } +} + +static void +local_add(parser_state *p, mrb_sym sym) +{ + if (!local_var_p(p, sym)) { + local_add_f(p, sym); + } +} + +static node* +locals_node(parser_state *p) +{ + return p->locals ? p->locals->car : NULL; +} + +/* (:scope (vars..) (prog...)) */ +static node* +new_scope(parser_state *p, node *body) +{ + return cons((node*)NODE_SCOPE, cons(locals_node(p), body)); +} + +/* (:begin prog...) */ +static node* +new_begin(parser_state *p, node *body) +{ + if (body) { + return list2((node*)NODE_BEGIN, body); + } + return cons((node*)NODE_BEGIN, 0); +} + +#define newline_node(n) (n) + +/* (:rescue body rescue else) */ +static node* +new_rescue(parser_state *p, node *body, node *resq, node *els) +{ + return list4((node*)NODE_RESCUE, body, resq, els); +} + +/* (:ensure body ensure) */ +static node* +new_ensure(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_ENSURE, cons(a, cons(0, b))); +} + +/* (:nil) */ +static node* +new_nil(parser_state *p) +{ + return list1((node*)NODE_NIL); +} + +/* (:true) */ +static node* +new_true(parser_state *p) +{ + return list1((node*)NODE_TRUE); +} + +/* (:false) */ +static node* +new_false(parser_state *p) +{ + return list1((node*)NODE_FALSE); +} + +/* (:alias new old) */ +static node* +new_alias(parser_state *p, mrb_sym a, mrb_sym b) +{ + return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b))); +} + +/* (:if cond then else) */ +static node* +new_if(parser_state *p, node *a, node *b, node *c) +{ + return list4((node*)NODE_IF, a, b, c); +} + +/* (:unless cond then else) */ +static node* +new_unless(parser_state *p, node *a, node *b, node *c) +{ + return list4((node*)NODE_IF, a, c, b); +} + +/* (:while cond body) */ +static node* +new_while(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_WHILE, cons(a, b)); +} + +/* (:until cond body) */ +static node* +new_until(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_UNTIL, cons(a, b)); +} + +/* (:for var obj body) */ +static node* +new_for(parser_state *p, node *v, node *o, node *b) +{ + return list4((node*)NODE_FOR, v, o, b); +} + +/* (:case a ((when ...) body) ((when...) body)) */ +static node* +new_case(parser_state *p, node *a, node *b) +{ + node *n = list2((node*)NODE_CASE, a); + node *n2 = n; + + while (n2->cdr) { + n2 = n2->cdr; + } + n2->cdr = b; + return n; +} + +/* (:postexe a) */ +static node* +new_postexe(parser_state *p, node *a) +{ + return cons((node*)NODE_POSTEXE, a); +} + +/* (:self) */ +static node* +new_self(parser_state *p) +{ + return list1((node*)NODE_SELF); +} + +/* (:call a b c) */ +static node* +new_call(parser_state *p, node *a, mrb_sym b, node *c) +{ + node *n = list4((node*)NODE_CALL, a, nsym(b), c); + NODE_LINENO(n, a); + return n; +} + +/* (:fcall self mid args) */ +static node* +new_fcall(parser_state *p, mrb_sym b, node *c) +{ + node *n = new_self(p); + NODE_LINENO(n, c); + n = list4((node*)NODE_FCALL, n, nsym(b), c); + NODE_LINENO(n, c); + return n; +} + +/* (:super . c) */ +static node* +new_super(parser_state *p, node *c) +{ + return cons((node*)NODE_SUPER, c); +} + +/* (:zsuper) */ +static node* +new_zsuper(parser_state *p) +{ + return list1((node*)NODE_ZSUPER); +} + +/* (:yield . c) */ +static node* +new_yield(parser_state *p, node *c) +{ + if (c) { + if (c->cdr) { + yyerror(p, "both block arg and actual block given"); + } + return cons((node*)NODE_YIELD, c->car); + } + return cons((node*)NODE_YIELD, 0); +} + +/* (:return . c) */ +static node* +new_return(parser_state *p, node *c) +{ + return cons((node*)NODE_RETURN, c); +} + +/* (:break . c) */ +static node* +new_break(parser_state *p, node *c) +{ + return cons((node*)NODE_BREAK, c); +} + +/* (:next . c) */ +static node* +new_next(parser_state *p, node *c) +{ + return cons((node*)NODE_NEXT, c); +} + +/* (:redo) */ +static node* +new_redo(parser_state *p) +{ + return list1((node*)NODE_REDO); +} + +/* (:retry) */ +static node* +new_retry(parser_state *p) +{ + return list1((node*)NODE_RETRY); +} + +/* (:dot2 a b) */ +static node* +new_dot2(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DOT2, cons(a, b)); +} + +/* (:dot3 a b) */ +static node* +new_dot3(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DOT3, cons(a, b)); +} + +/* (:colon2 b c) */ +static node* +new_colon2(parser_state *p, node *b, mrb_sym c) +{ + return cons((node*)NODE_COLON2, cons(b, nsym(c))); +} + +/* (:colon3 . c) */ +static node* +new_colon3(parser_state *p, mrb_sym c) +{ + return cons((node*)NODE_COLON3, nsym(c)); +} + +/* (:and a b) */ +static node* +new_and(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_AND, cons(a, b)); +} + +/* (:or a b) */ +static node* +new_or(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_OR, cons(a, b)); +} + +/* (:array a...) */ +static node* +new_array(parser_state *p, node *a) +{ + return cons((node*)NODE_ARRAY, a); +} + +/* (:splat . a) */ +static node* +new_splat(parser_state *p, node *a) +{ + return cons((node*)NODE_SPLAT, a); +} + +/* (:hash (k . v) (k . v)...) */ +static node* +new_hash(parser_state *p, node *a) +{ + return cons((node*)NODE_HASH, a); +} + +/* (:sym . a) */ +static node* +new_sym(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_SYM, nsym(sym)); +} + +static mrb_sym +new_strsym(parser_state *p, node* str) +{ + const char *s = (const char*)str->cdr->car; + size_t len = (size_t)str->cdr->cdr; + + return mrb_intern(p->mrb, s, len); +} + +/* (:lvar . a) */ +static node* +new_lvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_LVAR, nsym(sym)); +} + +/* (:gvar . a) */ +static node* +new_gvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_GVAR, nsym(sym)); +} + +/* (:ivar . a) */ +static node* +new_ivar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_IVAR, nsym(sym)); +} + +/* (:cvar . a) */ +static node* +new_cvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_CVAR, nsym(sym)); +} + +/* (:const . a) */ +static node* +new_const(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_CONST, nsym(sym)); +} + +/* (:undef a...) */ +static node* +new_undef(parser_state *p, mrb_sym sym) +{ + return list2((node*)NODE_UNDEF, nsym(sym)); +} + +/* (:class class super body) */ +static node* +new_class(parser_state *p, node *c, node *s, node *b) +{ + return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b)); +} + +/* (:sclass obj body) */ +static node* +new_sclass(parser_state *p, node *o, node *b) +{ + return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b)); +} + +/* (:module module body) */ +static node* +new_module(parser_state *p, node *m, node *b) +{ + return list3((node*)NODE_MODULE, m, cons(locals_node(p), b)); +} + +/* (:def m lv (arg . body)) */ +static node* +new_def(parser_state *p, mrb_sym m, node *a, node *b) +{ + return list5((node*)NODE_DEF, nsym(m), locals_node(p), a, b); +} + +/* (:sdef obj m lv (arg . body)) */ +static node* +new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b) +{ + return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b); +} + +/* (:arg . sym) */ +static node* +new_arg(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_ARG, nsym(sym)); +} + +/* (m o r m2 b) */ +/* m: (a b c) */ +/* o: ((a . e1) (b . e2)) */ +/* r: a */ +/* m2: (a b c) */ +/* b: a */ +static node* +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) +{ + node *n; + + n = cons(m2, nsym(blk)); + n = cons(nsym(rest), n); + n = cons(opt, n); + return cons(m, n); +} + +/* (:block_arg . a) */ +static node* +new_block_arg(parser_state *p, node *a) +{ + return cons((node*)NODE_BLOCK_ARG, a); +} + +/* (:block arg body) */ +static node* +new_block(parser_state *p, node *a, node *b) +{ + return list4((node*)NODE_BLOCK, locals_node(p), a, b); +} + +/* (:lambda arg body) */ +static node* +new_lambda(parser_state *p, node *a, node *b) +{ + return list4((node*)NODE_LAMBDA, locals_node(p), a, b); +} + +/* (:asgn lhs rhs) */ +static node* +new_asgn(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_ASGN, cons(a, b)); +} + +/* (:masgn mlhs=(pre rest post) mrhs) */ +static node* +new_masgn(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_MASGN, cons(a, b)); +} + +/* (:asgn lhs rhs) */ +static node* +new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) +{ + return list4((node*)NODE_OP_ASGN, a, nsym(op), b); +} + +/* (:int . i) */ +static node* +new_int(parser_state *p, const char *s, int base) +{ + return list3((node*)NODE_INT, (node*)strdup(s), (node*)(intptr_t)base); +} + +/* (:float . i) */ +static node* +new_float(parser_state *p, const char *s) +{ + return cons((node*)NODE_FLOAT, (node*)strdup(s)); +} + +/* (:str . (s . len)) */ +static node* +new_str(parser_state *p, const char *s, int len) +{ + return cons((node*)NODE_STR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); +} + +/* (:dstr . a) */ +static node* +new_dstr(parser_state *p, node *a) +{ + return cons((node*)NODE_DSTR, a); +} + +/* (:str . (s . len)) */ +static node* +new_xstr(parser_state *p, const char *s, int len) +{ + return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); +} + +/* (:xstr . a) */ +static node* +new_dxstr(parser_state *p, node *a) +{ + return cons((node*)NODE_DXSTR, a); +} + +/* (:dsym . a) */ +static node* +new_dsym(parser_state *p, node *a) +{ + return cons((node*)NODE_DSYM, new_dstr(p, a)); +} + +/* (:str . (a . a)) */ +static node* +new_regx(parser_state *p, const char *p1, const char* p2) +{ + return cons((node*)NODE_REGX, cons((node*)p1, (node*)p2)); +} + +/* (:dregx . a) */ +static node* +new_dregx(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DREGX, cons(a, b)); +} + +/* (:backref . n) */ +static node* +new_back_ref(parser_state *p, int n) +{ + return cons((node*)NODE_BACK_REF, (node*)(intptr_t)n); +} + +/* (:nthref . n) */ +static node* +new_nth_ref(parser_state *p, int n) +{ + return cons((node*)NODE_NTH_REF, (node*)(intptr_t)n); +} + +/* (:heredoc . a) */ +static node* +new_heredoc(parser_state *p) +{ + parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info)); + return cons((node*)NODE_HEREDOC, (node*)inf); +} + +static void +new_bv(parser_state *p, mrb_sym id) +{ +} + +static node* +new_literal_delim(parser_state *p) +{ + return cons((node*)NODE_LITERAL_DELIM, 0); +} + +/* (:words . a) */ +static node* +new_words(parser_state *p, node *a) +{ + return cons((node*)NODE_WORDS, a); +} + +/* (:symbols . a) */ +static node* +new_symbols(parser_state *p, node *a) +{ + return cons((node*)NODE_SYMBOLS, a); +} + +/* xxx ----------------------------- */ + +/* (:call a op) */ +static node* +call_uni_op(parser_state *p, node *recv, const char *m) +{ + return new_call(p, recv, intern_cstr(m), 0); +} + +/* (:call a op b) */ +static node* +call_bin_op(parser_state *p, node *recv, const char *m, node *arg1) +{ + return new_call(p, recv, intern_cstr(m), list1(list1(arg1))); +} + +static void +args_with_block(parser_state *p, node *a, node *b) +{ + if (b) { + if (a->cdr) { + yyerror(p, "both block arg and actual block given"); + } + a->cdr = b; + } +} + +static void +call_with_block(parser_state *p, node *a, node *b) +{ + node *n; + + if (a->car == (node*)NODE_SUPER || + a->car == (node*)NODE_ZSUPER) { + if (!a->cdr) a->cdr = cons(0, b); + else { + args_with_block(p, a->cdr, b); + } + } + else { + n = a->cdr->cdr->cdr; + if (!n->car) n->car = cons(0, b); + else { + args_with_block(p, n->car, b); + } + } +} + +static node* +negate_lit(parser_state *p, node *n) +{ + return cons((node*)NODE_NEGATE, n); +} + +static node* +cond(node *n) +{ + return n; +} + +static node* +ret_args(parser_state *p, node *n) +{ + if (n->cdr) { + yyerror(p, "block argument should not be given"); + return NULL; + } + if (!n->car->cdr) return n->car->car; + return new_array(p, n->car); +} + +static void +assignable(parser_state *p, node *lhs) +{ + if ((int)(intptr_t)lhs->car == NODE_LVAR) { + local_add(p, sym(lhs->cdr)); + } +} + +static node* +var_reference(parser_state *p, node *lhs) +{ + node *n; + + if ((int)(intptr_t)lhs->car == NODE_LVAR) { + if (!local_var_p(p, sym(lhs->cdr))) { + n = new_fcall(p, sym(lhs->cdr), 0); + cons_free(lhs); + return n; + } + } + + return lhs; +} + +typedef enum mrb_string_type string_type; + +static node* +new_strterm(parser_state *p, string_type type, int term, int paren) +{ + return cons((node*)(intptr_t)type, cons((node*)0, cons((node*)(intptr_t)paren, (node*)(intptr_t)term))); +} + +static void +end_strterm(parser_state *p) +{ + cons_free(p->lex_strterm->cdr->cdr); + cons_free(p->lex_strterm->cdr); + cons_free(p->lex_strterm); + p->lex_strterm = NULL; +} + +static parser_heredoc_info * +parsing_heredoc_inf(parser_state *p) +{ + node *nd = p->parsing_heredoc; + if (nd == NULL) + return NULL; + /* mrb_assert(nd->car->car == NODE_HEREDOC); */ + return (parser_heredoc_info*)nd->car->cdr; +} + +static void +heredoc_treat_nextline(parser_state *p) +{ + if (p->heredocs_from_nextline == NULL) + return; + if (p->parsing_heredoc == NULL) { + node *n; + p->parsing_heredoc = p->heredocs_from_nextline; + p->lex_strterm_before_heredoc = p->lex_strterm; + p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0); + n = p->all_heredocs; + if (n) { + while (n->cdr) + n = n->cdr; + n->cdr = p->parsing_heredoc; + } + else { + p->all_heredocs = p->parsing_heredoc; + } + } + else { + node *n, *m; + m = p->heredocs_from_nextline; + while (m->cdr) + m = m->cdr; + n = p->all_heredocs; + mrb_assert(n != NULL); + if (n == p->parsing_heredoc) { + m->cdr = n; + p->all_heredocs = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + else { + while (n->cdr != p->parsing_heredoc) { + n = n->cdr; + mrb_assert(n != NULL); + } + m->cdr = n->cdr; + n->cdr = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + } + p->heredocs_from_nextline = NULL; +} + +static void +heredoc_end(parser_state *p) +{ + p->parsing_heredoc = p->parsing_heredoc->cdr; + if (p->parsing_heredoc == NULL) { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + end_strterm(p); + p->lex_strterm = p->lex_strterm_before_heredoc; + p->lex_strterm_before_heredoc = NULL; + p->heredoc_end_now = TRUE; + } + else { + /* next heredoc */ + p->lex_strterm->car = (node*)(intptr_t)parsing_heredoc_inf(p)->type; + } +} +#define is_strterm_type(p,str_func) ((int)(intptr_t)((p)->lex_strterm->car) & (str_func)) + +/* xxx ----------------------------- */ + +%} + +%pure-parser +%parse-param {parser_state *p} +%lex-param {parser_state *p} + +%union { + node *nd; + mrb_sym id; + int num; + stack_type stack; + const struct vtable *vars; +} + +%token + keyword_class + keyword_module + keyword_def + keyword_begin + keyword_if + keyword_unless + keyword_while + keyword_until + keyword_for + +%token + keyword_undef + keyword_rescue + keyword_ensure + keyword_end + keyword_then + keyword_elsif + keyword_else + keyword_case + keyword_when + keyword_break + keyword_next + keyword_redo + keyword_retry + keyword_in + keyword_do + keyword_do_cond + keyword_do_block + keyword_do_LAMBDA + keyword_return + keyword_yield + keyword_super + keyword_self + keyword_nil + keyword_true + keyword_false + keyword_and + keyword_or + keyword_not + modifier_if + modifier_unless + modifier_while + modifier_until + modifier_rescue + keyword_alias + keyword_BEGIN + keyword_END + keyword__LINE__ + keyword__FILE__ + keyword__ENCODING__ + +%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL +%token tINTEGER tFLOAT tCHAR tXSTRING tREGEXP +%token tSTRING tSTRING_PART tSTRING_MID +%token tNTH_REF tBACK_REF +%token tREGEXP_END + +%type singleton string string_rep string_interp xstring regexp +%type literal numeric cpath symbol +%type top_compstmt top_stmts top_stmt +%type bodystmt compstmt stmts stmt expr arg primary command command_call method_call +%type expr_value arg_value primary_value +%type if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure +%type args call_args opt_call_args +%type paren_args opt_paren_args variable +%type command_args aref_args opt_block_arg block_arg var_ref var_lhs +%type command_asgn mrhs superclass block_call block_command +%type f_block_optarg f_block_opt +%type f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs +%type assoc_list assocs assoc undef_list backref for_var +%type block_param opt_block_param block_param_def f_opt +%type bv_decls opt_bv_decl bvar f_larglist lambda_body +%type brace_block cmd_brace_block do_block lhs none f_bad_arg +%type mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner +%type fsym sym basic_symbol operation operation2 operation3 +%type cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn +%type heredoc words symbols + +%token tUPLUS /* unary+ */ +%token tUMINUS /* unary- */ +%token tPOW /* ** */ +%token tCMP /* <=> */ +%token tEQ /* == */ +%token tEQQ /* === */ +%token tNEQ /* != */ +%token tGEQ /* >= */ +%token tLEQ /* <= */ +%token tANDOP tOROP /* && and || */ +%token tMATCH tNMATCH /* =~ and !~ */ +%token tDOT2 tDOT3 /* .. and ... */ +%token tAREF tASET /* [] and []= */ +%token tLSHFT tRSHFT /* << and >> */ +%token tCOLON2 /* :: */ +%token tCOLON3 /* :: at EXPR_BEG */ +%token tOP_ASGN /* +=, -= etc. */ +%token tASSOC /* => */ +%token tLPAREN /* ( */ +%token tLPAREN_ARG /* ( */ +%token tRPAREN /* ) */ +%token tLBRACK /* [ */ +%token tLBRACE /* { */ +%token tLBRACE_ARG /* { */ +%token tSTAR /* * */ +%token tAMPER /* & */ +%token tLAMBDA /* -> */ +%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG +%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG +%token tHEREDOC_BEG /* <<, <<- */ +%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM +%token tHD_STRING_PART tHD_STRING_MID + +/* + * precedence table + */ + +%nonassoc tLOWEST +%nonassoc tLBRACE_ARG + +%nonassoc modifier_if modifier_unless modifier_while modifier_until +%left keyword_or keyword_and +%right keyword_not +%right '=' tOP_ASGN +%left modifier_rescue +%right '?' ':' +%nonassoc tDOT2 tDOT3 +%left tOROP +%left tANDOP +%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH +%left '>' tGEQ '<' tLEQ +%left '|' '^' +%left '&' +%left tLSHFT tRSHFT +%left '+' '-' +%left '*' '/' '%' +%right tUMINUS_NUM tUMINUS +%right tPOW +%right '!' '~' tUPLUS + +%token tLAST_TOKEN + +%% +program : { + p->lstate = EXPR_BEG; + if (!p->locals) p->locals = cons(0,0); + } + top_compstmt + { + p->tree = new_scope(p, $2); + NODE_LINENO(p->tree, $2); + } + ; + +top_compstmt : top_stmts opt_terms + { + $$ = $1; + } + ; + +top_stmts : none + { + $$ = new_begin(p, 0); + } + | top_stmt + { + $$ = new_begin(p, $1); + NODE_LINENO($$, $1); + } + | top_stmts terms top_stmt + { + $$ = push($1, newline_node($3)); + } + | error top_stmt + { + $$ = new_begin(p, 0); + } + ; + +top_stmt : stmt + | keyword_BEGIN + { + $$ = local_switch(p); + } + '{' top_compstmt '}' + { + yyerror(p, "BEGIN not supported"); + local_resume(p, $2); + $$ = 0; + } + ; + +bodystmt : compstmt + opt_rescue + opt_else + opt_ensure + { + if ($2) { + $$ = new_rescue(p, $1, $2, $3); + NODE_LINENO($$, $1); + } + else if ($3) { + yywarn(p, "else without rescue is useless"); + $$ = push($1, $3); + } + else { + $$ = $1; + } + if ($4) { + if ($$) { + $$ = new_ensure(p, $$, $4); + } + else { + $$ = push($4, new_nil(p)); + } + } + } + ; + +compstmt : stmts opt_terms + { + $$ = $1; + } + ; + +stmts : none + { + $$ = new_begin(p, 0); + } + | stmt + { + $$ = new_begin(p, $1); + NODE_LINENO($$, $1); + } + | stmts terms stmt + { + $$ = push($1, newline_node($3)); + } + | error stmt + { + $$ = new_begin(p, $2); + } + ; + +stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym + { + $$ = new_alias(p, $2, $4); + } + | keyword_undef undef_list + { + $$ = $2; + } + | stmt modifier_if expr_value + { + $$ = new_if(p, cond($3), $1, 0); + } + | stmt modifier_unless expr_value + { + $$ = new_unless(p, cond($3), $1, 0); + } + | stmt modifier_while expr_value + { + $$ = new_while(p, cond($3), $1); + } + | stmt modifier_until expr_value + { + $$ = new_until(p, cond($3), $1); + } + | stmt modifier_rescue stmt + { + $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); + } + | keyword_END '{' compstmt '}' + { + yyerror(p, "END not suported"); + $$ = new_postexe(p, $3); + } + | command_asgn + | mlhs '=' command_call + { + $$ = new_masgn(p, $1, $3); + } + | var_lhs tOP_ASGN command_call + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call + { + yyerror(p, "constant re-assignment"); + $$ = 0; + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | backref tOP_ASGN command_call + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | lhs '=' mrhs + { + $$ = new_asgn(p, $1, new_array(p, $3)); + } + | mlhs '=' arg_value + { + $$ = new_masgn(p, $1, $3); + } + | mlhs '=' mrhs + { + $$ = new_masgn(p, $1, new_array(p, $3)); + } + | expr + ; + +command_asgn : lhs '=' command_call + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' command_asgn + { + $$ = new_asgn(p, $1, $3); + } + ; + + +expr : command_call + | expr keyword_and expr + { + $$ = new_and(p, $1, $3); + } + | expr keyword_or expr + { + $$ = new_or(p, $1, $3); + } + | keyword_not opt_nl expr + { + $$ = call_uni_op(p, cond($3), "!"); + } + | '!' command_call + { + $$ = call_uni_op(p, cond($2), "!"); + } + | arg + ; + +expr_value : expr + { + if (!$1) $$ = new_nil(p); + else $$ = $1; + } + ; + +command_call : command + | block_command + ; + +block_command : block_call + | block_call dot_or_colon operation2 command_args + ; + +cmd_brace_block : tLBRACE_ARG + { + local_nest(p); + } + opt_block_param + compstmt + '}' + { + $$ = new_block(p, $3, $4); + local_unnest(p); + } + ; + +command : operation command_args %prec tLOWEST + { + $$ = new_fcall(p, $1, $2); + } + | operation command_args cmd_brace_block + { + args_with_block(p, $2, $3); + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value '.' operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | keyword_super command_args + { + $$ = new_super(p, $2); + } + | keyword_yield command_args + { + $$ = new_yield(p, $2); + } + | keyword_return call_args + { + $$ = new_return(p, ret_args(p, $2)); + } + | keyword_break call_args + { + $$ = new_break(p, ret_args(p, $2)); + } + | keyword_next call_args + { + $$ = new_next(p, ret_args(p, $2)); + } + ; + +mlhs : mlhs_basic + { + $$ = $1; + } + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_inner : mlhs_basic + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_basic : mlhs_list + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = list1(push($1,$2)); + } + | mlhs_list tSTAR mlhs_node + { + $$ = list2($1, $3); + } + | mlhs_list tSTAR mlhs_node ',' mlhs_post + { + $$ = list3($1, $3, $5); + } + | mlhs_list tSTAR + { + $$ = list2($1, new_nil(p)); + } + | mlhs_list tSTAR ',' mlhs_post + { + $$ = list3($1, new_nil(p), $4); + } + | tSTAR mlhs_node + { + $$ = list2(0, $2); + } + | tSTAR mlhs_node ',' mlhs_post + { + $$ = list3(0, $2, $4); + } + | tSTAR + { + $$ = list2(0, new_nil(p)); + } + | tSTAR ',' mlhs_post + { + $$ = list3(0, new_nil(p), $3); + } + ; + +mlhs_item : mlhs_node + | tLPAREN mlhs_inner rparen + { + $$ = new_masgn(p, $2, NULL); + } + ; + +mlhs_list : mlhs_item ',' + { + $$ = list1($1); + } + | mlhs_list mlhs_item ',' + { + $$ = push($1, $2); + } + ; + +mlhs_post : mlhs_item + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = push($1, $2); + } + ; + +mlhs_node : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +lhs : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +cname : tIDENTIFIER + { + yyerror(p, "class/module name must be CONSTANT"); + } + | tCONSTANT + ; + +cpath : tCOLON3 cname + { + $$ = cons((node*)1, nsym($2)); + } + | cname + { + $$ = cons((node*)0, nsym($1)); + } + | primary_value tCOLON2 cname + { + $$ = cons($1, nsym($3)); + } + ; + +fname : tIDENTIFIER + | tCONSTANT + | tFID + | op + { + p->lstate = EXPR_ENDFN; + $$ = $1; + } + | reswords + { + p->lstate = EXPR_ENDFN; + $$ = $1; + } + ; + +fsym : fname + | basic_symbol + ; + +undef_list : fsym + { + $$ = new_undef(p, $1); + } + | undef_list ',' {p->lstate = EXPR_FNAME;} fsym + { + $$ = push($1, nsym($4)); + } + ; + +op : '|' { $$ = intern_c('|'); } + | '^' { $$ = intern_c('^'); } + | '&' { $$ = intern_c('&'); } + | tCMP { $$ = intern("<=>",3); } + | tEQ { $$ = intern("==",2); } + | tEQQ { $$ = intern("===",3); } + | tMATCH { $$ = intern("=~",2); } + | tNMATCH { $$ = intern("!~",2); } + | '>' { $$ = intern_c('>'); } + | tGEQ { $$ = intern(">=",2); } + | '<' { $$ = intern_c('<'); } + | tLEQ { $$ = intern("<=",2); } + | tNEQ { $$ = intern("!=",2); } + | tLSHFT { $$ = intern("<<",2); } + | tRSHFT { $$ = intern(">>",2); } + | '+' { $$ = intern_c('+'); } + | '-' { $$ = intern_c('-'); } + | '*' { $$ = intern_c('*'); } + | tSTAR { $$ = intern_c('*'); } + | '/' { $$ = intern_c('/'); } + | '%' { $$ = intern_c('%'); } + | tPOW { $$ = intern("**",2); } + | '!' { $$ = intern_c('!'); } + | '~' { $$ = intern_c('~'); } + | tUPLUS { $$ = intern("+@",2); } + | tUMINUS { $$ = intern("-@",2); } + | tAREF { $$ = intern("[]",2); } + | tASET { $$ = intern("[]=",3); } + | '`' { $$ = intern_c('`'); } + ; + +reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ + | keyword_BEGIN | keyword_END + | keyword_alias | keyword_and | keyword_begin + | keyword_break | keyword_case | keyword_class | keyword_def + | keyword_do | keyword_else | keyword_elsif + | keyword_end | keyword_ensure | keyword_false + | keyword_for | keyword_in | keyword_module | keyword_next + | keyword_nil | keyword_not | keyword_or | keyword_redo + | keyword_rescue | keyword_retry | keyword_return | keyword_self + | keyword_super | keyword_then | keyword_true | keyword_undef + | keyword_when | keyword_yield | keyword_if | keyword_unless + | keyword_while | keyword_until + ; + +arg : lhs '=' arg + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' arg modifier_rescue arg + { + $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | var_lhs tOP_ASGN arg + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | var_lhs tOP_ASGN arg modifier_rescue arg + { + $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | tCOLON3 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | backref tOP_ASGN arg + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | arg tDOT2 arg + { + $$ = new_dot2(p, $1, $3); + } + | arg tDOT3 arg + { + $$ = new_dot3(p, $1, $3); + } + | arg '+' arg + { + $$ = call_bin_op(p, $1, "+", $3); + } + | arg '-' arg + { + $$ = call_bin_op(p, $1, "-", $3); + } + | arg '*' arg + { + $$ = call_bin_op(p, $1, "*", $3); + } + | arg '/' arg + { + $$ = call_bin_op(p, $1, "/", $3); + } + | arg '%' arg + { + $$ = call_bin_op(p, $1, "%", $3); + } + | arg tPOW arg + { + $$ = call_bin_op(p, $1, "**", $3); + } + | tUMINUS_NUM tINTEGER tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUMINUS_NUM tFLOAT tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUPLUS arg + { + $$ = call_uni_op(p, $2, "+@"); + } + | tUMINUS arg + { + $$ = call_uni_op(p, $2, "-@"); + } + | arg '|' arg + { + $$ = call_bin_op(p, $1, "|", $3); + } + | arg '^' arg + { + $$ = call_bin_op(p, $1, "^", $3); + } + | arg '&' arg + { + $$ = call_bin_op(p, $1, "&", $3); + } + | arg tCMP arg + { + $$ = call_bin_op(p, $1, "<=>", $3); + } + | arg '>' arg + { + $$ = call_bin_op(p, $1, ">", $3); + } + | arg tGEQ arg + { + $$ = call_bin_op(p, $1, ">=", $3); + } + | arg '<' arg + { + $$ = call_bin_op(p, $1, "<", $3); + } + | arg tLEQ arg + { + $$ = call_bin_op(p, $1, "<=", $3); + } + | arg tEQ arg + { + $$ = call_bin_op(p, $1, "==", $3); + } + | arg tEQQ arg + { + $$ = call_bin_op(p, $1, "===", $3); + } + | arg tNEQ arg + { + $$ = call_bin_op(p, $1, "!=", $3); + } + | arg tMATCH arg + { + $$ = call_bin_op(p, $1, "=~", $3); + } + | arg tNMATCH arg + { + $$ = call_bin_op(p, $1, "!~", $3); + } + | '!' arg + { + $$ = call_uni_op(p, cond($2), "!"); + } + | '~' arg + { + $$ = call_uni_op(p, cond($2), "~"); + } + | arg tLSHFT arg + { + $$ = call_bin_op(p, $1, "<<", $3); + } + | arg tRSHFT arg + { + $$ = call_bin_op(p, $1, ">>", $3); + } + | arg tANDOP arg + { + $$ = new_and(p, $1, $3); + } + | arg tOROP arg + { + $$ = new_or(p, $1, $3); + } + | arg '?' arg opt_nl ':' arg + { + $$ = new_if(p, cond($1), $3, $6); + } + | primary + { + $$ = $1; + } + ; + +arg_value : arg + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +aref_args : none + | args trailer + { + $$ = $1; + NODE_LINENO($$, $1); + } + | args ',' assocs trailer + { + $$ = push($1, new_hash(p, $3)); + } + | assocs trailer + { + $$ = cons(new_hash(p, $1), 0); + NODE_LINENO($$, $1); + } + ; + +paren_args : '(' opt_call_args rparen + { + $$ = $2; + } + ; + +opt_paren_args : none + | paren_args + ; + +opt_call_args : none + | call_args + | args ',' + { + $$ = cons($1,0); + NODE_LINENO($$, $1); + } + | args ',' assocs ',' + { + $$ = cons(push($1, new_hash(p, $3)), 0); + NODE_LINENO($$, $1); + } + | assocs ',' + { + $$ = cons(list1(new_hash(p, $1)), 0); + NODE_LINENO($$, $1); + } + ; + +call_args : command + { + $$ = cons(list1($1), 0); + NODE_LINENO($$, $1); + } + | args opt_block_arg + { + $$ = cons($1, $2); + NODE_LINENO($$, $1); + } + | assocs opt_block_arg + { + $$ = cons(list1(new_hash(p, $1)), $2); + NODE_LINENO($$, $1); + } + | args ',' assocs opt_block_arg + { + $$ = cons(push($1, new_hash(p, $3)), $4); + NODE_LINENO($$, $1); + } + | block_arg + { + $$ = cons(0, $1); + NODE_LINENO($$, $1); + } + ; + +command_args : { + $$ = p->cmdarg_stack; + CMDARG_PUSH(1); + } + call_args + { + p->cmdarg_stack = $1; + $$ = $2; + } + ; + +block_arg : tAMPER arg_value + { + $$ = new_block_arg(p, $2); + } + ; + +opt_block_arg : ',' block_arg + { + $$ = $2; + } + | none + { + $$ = 0; + } + ; + +args : arg_value + { + $$ = cons($1, 0); + NODE_LINENO($$, $1); + } + | tSTAR arg_value + { + $$ = cons(new_splat(p, $2), 0); + NODE_LINENO($$, $2); + } + | args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | args ',' heredoc_bodies arg_value + { + $$ = push($1, $4); + } + | args ',' heredoc_bodies tSTAR arg_value + { + $$ = push($1, new_splat(p, $5)); + } + ; + +mrhs : args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | tSTAR arg_value + { + $$ = list1(new_splat(p, $2)); + } + ; + +primary : literal + | string + | xstring + | regexp + | heredoc + | var_ref + | backref + | tFID + { + $$ = new_fcall(p, $1, 0); + } + | keyword_begin + { + $$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + bodystmt + keyword_end + { + p->cmdarg_stack = $2; + $$ = $3; + } + | tLPAREN_ARG + { + $$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + expr {p->lstate = EXPR_ENDARG;} rparen + { + p->cmdarg_stack = $2; + $$ = $3; + } + | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen + { + $$ = 0; + } + | tLPAREN compstmt ')' + { + $$ = $2; + } + | primary_value tCOLON2 tCONSTANT + { + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + $$ = new_colon3(p, $2); + } + | tLBRACK aref_args ']' + { + $$ = new_array(p, $2); + NODE_LINENO($$, $2); + } + | tLBRACE assoc_list '}' + { + $$ = new_hash(p, $2); + NODE_LINENO($$, $2); + } + | keyword_return + { + $$ = new_return(p, 0); + } + | keyword_yield '(' call_args rparen + { + $$ = new_yield(p, $3); + } + | keyword_yield '(' rparen + { + $$ = new_yield(p, 0); + } + | keyword_yield + { + $$ = new_yield(p, 0); + } + | keyword_not '(' expr rparen + { + $$ = call_uni_op(p, cond($3), "!"); + } + | keyword_not '(' rparen + { + $$ = call_uni_op(p, new_nil(p), "!"); + } + | operation brace_block + { + $$ = new_fcall(p, $1, cons(0, $2)); + } + | method_call + | method_call brace_block + { + call_with_block(p, $1, $2); + $$ = $1; + } + | tLAMBDA + { + local_nest(p); + $$ = p->lpar_beg; + p->lpar_beg = ++p->paren_nest; + } + f_larglist + { + $$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + lambda_body + { + p->lpar_beg = $2; + $$ = new_lambda(p, $3, $5); + local_unnest(p); + p->cmdarg_stack = $4; + } + | keyword_if expr_value then + compstmt + if_tail + keyword_end + { + $$ = new_if(p, cond($2), $4, $5); + SET_LINENO($$, $1); + } + | keyword_unless expr_value then + compstmt + opt_else + keyword_end + { + $$ = new_unless(p, cond($2), $4, $5); + SET_LINENO($$, $1); + } + | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_while(p, cond($3), $6); + SET_LINENO($$, $1); + } + | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_until(p, cond($3), $6); + SET_LINENO($$, $1); + } + | keyword_case expr_value opt_terms + case_body + keyword_end + { + $$ = new_case(p, $2, $4); + } + | keyword_case opt_terms case_body keyword_end + { + $$ = new_case(p, 0, $3); + } + | keyword_for for_var keyword_in + {COND_PUSH(1);} + expr_value do + {COND_POP();} + compstmt + keyword_end + { + $$ = new_for(p, $2, $5, $8); + SET_LINENO($$, $1); + } + | keyword_class + cpath superclass + { + if (p->in_def || p->in_single) + yyerror(p, "class definition in method body"); + $$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_class(p, $2, $3, $5); + SET_LINENO($$, $1); + local_resume(p, $4); + } + | keyword_class + tLSHFT expr + { + $$ = p->in_def; + p->in_def = 0; + } + term + { + $$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); + p->in_single = 0; + } + bodystmt + keyword_end + { + $$ = new_sclass(p, $3, $7); + SET_LINENO($$, $1); + local_resume(p, $6->car); + p->in_def = $4; + p->in_single = (int)(intptr_t)$6->cdr; + } + | keyword_module + cpath + { + if (p->in_def || p->in_single) + yyerror(p, "module definition in method body"); + $$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_module(p, $2, $4); + SET_LINENO($$, $1); + local_resume(p, $3); + } + | keyword_def fname + { + $$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + { + p->in_def++; + $$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_def(p, $2, $5, $6); + SET_LINENO($$, $1); + local_resume(p, $4); + p->in_def--; + p->cmdarg_stack = $3; + } + | keyword_def singleton dot_or_colon + { + p->lstate = EXPR_FNAME; + $$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + fname + { + p->in_single++; + p->lstate = EXPR_ENDFN; /* force for args */ + $$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_sdef(p, $2, $5, $7, $8); + SET_LINENO($$, $1); + local_resume(p, $6); + p->in_single--; + p->cmdarg_stack = $4; + } + | keyword_break + { + $$ = new_break(p, 0); + } + | keyword_next + { + $$ = new_next(p, 0); + } + | keyword_redo + { + $$ = new_redo(p); + } + | keyword_retry + { + $$ = new_retry(p); + } + ; + +primary_value : primary + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +then : term + | keyword_then + | term keyword_then + ; + +do : term + | keyword_do_cond + ; + +if_tail : opt_else + | keyword_elsif expr_value then + compstmt + if_tail + { + $$ = new_if(p, cond($2), $4, $5); + } + ; + +opt_else : none + | keyword_else compstmt + { + $$ = $2; + } + ; + +for_var : lhs + { + $$ = list1(list1($1)); + } + | mlhs + ; + +f_marg : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_marg_list : f_marg + { + $$ = list1($1); + } + | f_marg_list ',' f_marg + { + $$ = push($1, $3); + } + ; + +f_margs : f_marg_list + { + $$ = list3($1,0,0); + } + | f_marg_list ',' tSTAR f_norm_arg + { + $$ = list3($1, new_arg(p, $4), 0); + } + | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3($1, new_arg(p, $4), $6); + } + | f_marg_list ',' tSTAR + { + $$ = list3($1, (node*)-1, 0); + } + | f_marg_list ',' tSTAR ',' f_marg_list + { + $$ = list3($1, (node*)-1, $5); + } + | tSTAR f_norm_arg + { + $$ = list3(0, new_arg(p, $2), 0); + } + | tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3(0, new_arg(p, $2), $4); + } + | tSTAR + { + $$ = list3(0, (node*)-1, 0); + } + | tSTAR ',' f_marg_list + { + $$ = list3(0, (node*)-1, $3); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_block_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' + { + $$ = new_args(p, $1, 0, 1, 0, 0); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_block_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + ; + +opt_block_param : none + | block_param_def + { + p->cmd_start = TRUE; + $$ = $1; + } + ; + +block_param_def : '|' opt_bv_decl '|' + { + $$ = 0; + } + | tOROP + { + $$ = 0; + } + | '|' block_param opt_bv_decl '|' + { + $$ = $2; + } + ; + + +opt_bv_decl : opt_nl + { + $$ = 0; + } + | opt_nl ';' bv_decls opt_nl + { + $$ = 0; + } + ; + +bv_decls : bvar + | bv_decls ',' bvar + ; + +bvar : tIDENTIFIER + { + local_add_f(p, $1); + new_bv(p, $1); + } + | f_bad_arg + ; + +f_larglist : '(' f_args opt_bv_decl ')' + { + $$ = $2; + } + | f_args + { + $$ = $1; + } + ; + +lambda_body : tLAMBEG compstmt '}' + { + $$ = $2; + } + | keyword_do_LAMBDA compstmt keyword_end + { + $$ = $2; + } + ; + +do_block : keyword_do_block + { + local_nest(p); + } + opt_block_param + compstmt + keyword_end + { + $$ = new_block(p,$3,$4); + local_unnest(p); + } + ; + +block_call : command do_block + { + if ($1->car == (node*)NODE_YIELD) { + yyerror(p, "block given to yield"); + } + else { + call_with_block(p, $1, $2); + } + $$ = $1; + } + | block_call dot_or_colon operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | block_call dot_or_colon operation2 opt_paren_args brace_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + | block_call dot_or_colon operation2 command_args do_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + ; + +method_call : operation paren_args + { + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation3 + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | primary_value tCOLON2 paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | keyword_super paren_args + { + $$ = new_super(p, $2); + } + | keyword_super + { + $$ = new_zsuper(p); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + ; + +brace_block : '{' + { + local_nest(p); + $$ = p->lineno; + } + opt_block_param + compstmt '}' + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $2); + local_unnest(p); + } + | keyword_do + { + local_nest(p); + $$ = p->lineno; + } + opt_block_param + compstmt keyword_end + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $2); + local_unnest(p); + } + ; + +case_body : keyword_when args then + compstmt + cases + { + $$ = cons(cons($2, $4), $5); + } + ; + +cases : opt_else + { + if ($1) { + $$ = cons(cons(0, $1), 0); + } + else { + $$ = 0; + } + } + | case_body + ; + +opt_rescue : keyword_rescue exc_list exc_var then + compstmt + opt_rescue + { + $$ = list1(list3($2, $3, $5)); + if ($6) $$ = append($$, $6); + } + | none + ; + +exc_list : arg_value + { + $$ = list1($1); + } + | mrhs + | none + ; + +exc_var : tASSOC lhs + { + $$ = $2; + } + | none + ; + +opt_ensure : keyword_ensure compstmt + { + $$ = $2; + } + | none + ; + +literal : numeric + | symbol + | words + | symbols + ; + +string : tCHAR + | tSTRING + | tSTRING_BEG tSTRING + { + $$ = $2; + } + | tSTRING_BEG string_rep tSTRING + { + $$ = new_dstr(p, push($2, $3)); + } + ; + +string_rep : string_interp + | string_rep string_interp + { + $$ = append($1, $2); + } + ; + +string_interp : tSTRING_MID + { + $$ = list1($1); + } + | tSTRING_PART + { + $$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + p->lex_strterm = $2; + $$ = list2($1, $3); + } + | tLITERAL_DELIM + { + $$ = list1(new_literal_delim(p)); + } + | tHD_LITERAL_DELIM heredoc_bodies + { + $$ = list1(new_literal_delim(p)); + } + ; + +xstring : tXSTRING_BEG tXSTRING + { + $$ = $2; + } + | tXSTRING_BEG string_rep tXSTRING + { + $$ = new_dxstr(p, push($2, $3)); + } + ; + +regexp : tREGEXP_BEG tREGEXP + { + $$ = $2; + } + | tREGEXP_BEG string_rep tREGEXP + { + $$ = new_dregx(p, $2, $3); + } + ; + +heredoc : tHEREDOC_BEG + ; + +opt_heredoc_bodies : /* none */ + | heredoc_bodies + ; + +heredoc_bodies : heredoc_body + | heredoc_bodies heredoc_body + ; + +heredoc_body : tHEREDOC_END + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, new_str(p, "", 0)); + heredoc_end(p); + } + | heredoc_string_rep tHEREDOC_END + { + heredoc_end(p); + } + ; + +heredoc_string_rep : heredoc_string_interp + | heredoc_string_rep heredoc_string_interp + ; + +heredoc_string_interp : tHD_STRING_MID + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, $1); + heredoc_treat_nextline(p); + } + | tHD_STRING_PART + { + $$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + p->lex_strterm = $2; + inf->doc = push(push(inf->doc, $1), $3); + } + ; + +words : tWORDS_BEG tSTRING + { + $$ = new_words(p, list1($2)); + } + | tWORDS_BEG string_rep tSTRING + { + $$ = new_words(p, push($2, $3)); + } + ; + + +symbol : basic_symbol + { + $$ = new_sym(p, $1); + } + | tSYMBEG tSTRING_BEG string_interp tSTRING + { + p->lstate = EXPR_END; + $$ = new_dsym(p, push($3, $4)); + } + ; + +basic_symbol : tSYMBEG sym + { + p->lstate = EXPR_END; + $$ = $2; + } + ; + +sym : fname + | tIVAR + | tGVAR + | tCVAR + | tSTRING + { + $$ = new_strsym(p, $1); + } + | tSTRING_BEG tSTRING + { + $$ = new_strsym(p, $2); + } + ; + +symbols : tSYMBOLS_BEG tSTRING + { + $$ = new_symbols(p, list1($2)); + } + | tSYMBOLS_BEG string_rep tSTRING + { + $$ = new_symbols(p, push($2, $3)); + } + ; + +numeric : tINTEGER + | tFLOAT + | tUMINUS_NUM tINTEGER %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + | tUMINUS_NUM tFLOAT %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + ; + +variable : tIDENTIFIER + { + $$ = new_lvar(p, $1); + } + | tIVAR + { + $$ = new_ivar(p, $1); + } + | tGVAR + { + $$ = new_gvar(p, $1); + } + | tCVAR + { + $$ = new_cvar(p, $1); + } + | tCONSTANT + { + $$ = new_const(p, $1); + } + ; + +var_lhs : variable + { + assignable(p, $1); + } + ; + +var_ref : variable + { + $$ = var_reference(p, $1); + } + | keyword_nil + { + $$ = new_nil(p); + } + | keyword_self + { + $$ = new_self(p); + } + | keyword_true + { + $$ = new_true(p); + } + | keyword_false + { + $$ = new_false(p); + } + | keyword__FILE__ + { + if (!p->filename) { + p->filename = "(null)"; + } + $$ = new_str(p, p->filename, strlen(p->filename)); + } + | keyword__LINE__ + { + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", p->lineno); + $$ = new_int(p, buf, 10); + } + ; + +backref : tNTH_REF + | tBACK_REF + ; + +superclass : term + { + $$ = 0; + } + | '<' + { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + expr_value term + { + $$ = $3; + } + | error term + { + yyerrok; + $$ = 0; + } + ; + +f_arglist : '(' f_args rparen + { + $$ = $2; + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + | f_args term + { + $$ = $1; + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + | /* none */ + { + local_add_f(p, 0); + $$ = new_args(p, 0, 0, 0, 0, 0); + } + ; + +f_bad_arg : tCONSTANT + { + yyerror(p, "formal argument cannot be a constant"); + $$ = 0; + } + | tIVAR + { + yyerror(p, "formal argument cannot be an instance variable"); + $$ = 0; + } + | tGVAR + { + yyerror(p, "formal argument cannot be a global variable"); + $$ = 0; + } + | tCVAR + { + yyerror(p, "formal argument cannot be a class variable"); + $$ = 0; + } + ; + +f_norm_arg : f_bad_arg + { + $$ = 0; + } + | tIDENTIFIER + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_arg_item : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_arg : f_arg_item + { + $$ = list1($1); + } + | f_arg ',' f_arg_item + { + $$ = push($1, $3); + } + ; + +f_opt_asgn : tIDENTIFIER '=' + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_opt : f_opt_asgn arg_value + { + $$ = cons(nsym($1), $2); + } + ; + +f_block_opt : f_opt_asgn primary_value + { + $$ = cons(nsym($1), $2); + } + ; + +f_block_optarg : f_block_opt + { + $$ = list1($1); + } + | f_block_optarg ',' f_block_opt + { + $$ = push($1, $3); + } + ; + +f_optarg : f_opt + { + $$ = list1($1); + } + | f_optarg ',' f_opt + { + $$ = push($1, $3); + } + ; + +restarg_mark : '*' + | tSTAR + ; + +f_rest_arg : restarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + | restarg_mark + { + local_add_f(p, 0); + $$ = -1; + } + ; + +blkarg_mark : '&' + | tAMPER + ; + +f_block_arg : blkarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + ; + +opt_f_block_arg : ',' f_block_arg + { + $$ = $2; + } + | none + { + local_add_f(p, 0); + $$ = 0; + } + ; + +singleton : var_ref + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + | '(' {p->lstate = EXPR_BEG;} expr rparen + { + if ($3 == 0) { + yyerror(p, "can't define singleton method for ()."); + } + else { + switch ((enum node_type)(int)(intptr_t)$3->car) { + case NODE_STR: + case NODE_DSTR: + case NODE_XSTR: + case NODE_DXSTR: + case NODE_DREGX: + case NODE_MATCH: + case NODE_FLOAT: + case NODE_ARRAY: + case NODE_HEREDOC: + yyerror(p, "can't define singleton method for literals"); + default: + break; + } + } + $$ = $3; + } + ; + +assoc_list : none + | assocs trailer + { + $$ = $1; + } + ; + +assocs : assoc + { + $$ = list1($1); + NODE_LINENO($$, $1); + } + | assocs ',' assoc + { + $$ = push($1, $3); + } + ; + +assoc : arg_value tASSOC arg_value + { + $$ = cons($1, $3); + } + | tLABEL arg_value + { + $$ = cons(new_sym(p, $1), $2); + } + ; + +operation : tIDENTIFIER + | tCONSTANT + | tFID + ; + +operation2 : tIDENTIFIER + | tCONSTANT + | tFID + | op + ; + +operation3 : tIDENTIFIER + | tFID + | op + ; + +dot_or_colon : '.' + | tCOLON2 + ; + +opt_terms : /* none */ + | terms + ; + +opt_nl : /* none */ + | nl + ; + +rparen : opt_nl ')' + ; + +rbracket : opt_nl ']' + ; + +trailer : /* none */ + | nl + | ',' + ; + +term : ';' {yyerrok;} + | nl + ; + +nl : '\n' + { + p->lineno++; + p->column = 0; + } + opt_heredoc_bodies + +terms : term + | terms ';' {yyerrok;} + ; + +none : /* none */ + { + $$ = 0; + } + ; +%% +#define yylval (*((YYSTYPE*)(p->ylval))) + +static void +yyerror(parser_state *p, const char *s) +{ + char* c; + int n; + + if (! p->capture_errors) { +#ifdef ENABLE_STDIO + if (p->filename) { + fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + } + else { + fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + } +#endif + } + else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) { + n = strlen(s); + c = (char *)parser_palloc(p, n + 1); + memcpy(c, s, n + 1); + p->error_buffer[p->nerr].message = c; + p->error_buffer[p->nerr].lineno = p->lineno; + p->error_buffer[p->nerr].column = p->column; + } + p->nerr++; +} + +static void +yyerror_i(parser_state *p, const char *fmt, int i) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), fmt, i); + yyerror(p, buf); +} + +static void +yywarn(parser_state *p, const char *s) +{ + char* c; + int n; + + if (! p->capture_errors) { +#ifdef ENABLE_STDIO + if (p->filename) { + fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + } + else { + fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + } +#endif + } + else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) { + n = strlen(s); + c = (char *)parser_palloc(p, n + 1); + memcpy(c, s, n + 1); + p->warn_buffer[p->nwarn].message = c; + p->warn_buffer[p->nwarn].lineno = p->lineno; + p->warn_buffer[p->nwarn].column = p->column; + } + p->nwarn++; +} + +static void +yywarning(parser_state *p, const char *s) +{ + yywarn(p, s); +} + +static void +yywarning_s(parser_state *p, const char *fmt, const char *s) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), fmt, s); + yywarning(p, buf); +} + +static void +backref_error(parser_state *p, node *n) +{ + int c; + + c = (int)(intptr_t)n->car; + + if (c == NODE_NTH_REF) { + yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr); + } + else if (c == NODE_BACK_REF) { + yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); + } + else { + mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); + } +} + +static void pushback(parser_state *p, int c); +static mrb_bool peeks(parser_state *p, const char *s); +static mrb_bool skips(parser_state *p, const char *s); + +static inline int +nextc(parser_state *p) +{ + int c; + + if (p->pb) { + node *tmp; + + c = (int)(intptr_t)p->pb->car; + tmp = p->pb; + p->pb = p->pb->cdr; + cons_free(tmp); + } + else { +#ifdef ENABLE_STDIO + if (p->f) { + if (feof(p->f)) goto eof; + c = fgetc(p->f); + if (c == EOF) goto eof; + } + else +#endif + if (!p->s || p->s >= p->send) { + goto eof; + } + else { + c = (unsigned char)*p->s++; + } + } + if (c >= 0) { + p->column++; + } + if (c == '\r') { + c = nextc(p); + if (c != '\n') { + pushback(p, c); + return '\r'; + } + return c; + } + return c; + + eof: + if (!p->cxt) return -1; + else { + if (p->cxt->partial_hook(p) < 0) + return -1; /* end of program(s) */ + return -2; /* end of a file in the program files */ + } +} + +static void +pushback(parser_state *p, int c) +{ + if (c >= 0) { + p->column--; + } + p->pb = cons((node*)(intptr_t)c, p->pb); +} + +static void +skip(parser_state *p, char term) +{ + int c; + + for (;;) { + c = nextc(p); + if (c < 0) break; + if (c == term) break; + } +} + +static int +peekc_n(parser_state *p, int n) +{ + node *list = 0; + int c0; + + do { + c0 = nextc(p); + if (c0 == -1) return c0; /* do not skip partial EOF */ + list = push(list, (node*)(intptr_t)c0); + } while(n--); + if (p->pb) { + p->pb = append((node*)list, p->pb); + } + else { + p->pb = list; + } + return c0; +} + +static mrb_bool +peek_n(parser_state *p, int c, int n) +{ + return peekc_n(p, n) == c && c >= 0; +} +#define peek(p,c) peek_n((p), (c), 0) + +static mrb_bool +peeks(parser_state *p, const char *s) +{ + int len = strlen(s); + +#ifdef ENABLE_STDIO + if (p->f) { + int n = 0; + while (*s) { + if (!peek_n(p, *s++, n++)) return FALSE; + } + return TRUE; + } + else +#endif + if (p->s && p->s + len <= p->send) { + if (memcmp(p->s, s, len) == 0) return TRUE; + } + return FALSE; +} + +static mrb_bool +skips(parser_state *p, const char *s) +{ + int c; + + for (;;) { + /* skip until first char */ + for (;;) { + c = nextc(p); + if (c < 0) return c; + if (c == '\n') { + p->lineno++; + p->column = 0; + } + if (c == *s) break; + } + s++; + if (peeks(p, s)) { + int len = strlen(s); + + while (len--) { + if (nextc(p) == '\n') { + p->lineno++; + p->column = 0; + } + } + return TRUE; + } + else{ + s--; + } + } + return FALSE; +} + + +static int +newtok(parser_state *p) +{ + p->bidx = 0; + return p->column - 1; +} + +static void +tokadd(parser_state *p, int32_t c) +{ + char utf8[4]; + unsigned len; + + /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */ + if (c >= 0) { + /* Single byte from source or non-Unicode escape */ + utf8[0] = (char)c; + len = 1; + } + else { + /* Unicode character */ + c = -c; + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + } + if (p->bidx+len <= MRB_PARSER_BUF_SIZE) { + unsigned i; + for (i = 0; i < len; i++) { + p->buf[p->bidx++] = utf8[i]; + } + } +} + +static int +toklast(parser_state *p) +{ + return p->buf[p->bidx-1]; +} + +static void +tokfix(parser_state *p) +{ + if (p->bidx >= MRB_PARSER_BUF_SIZE) { + yyerror(p, "string too long (truncated)"); + } + p->buf[p->bidx] = '\0'; +} + +static const char* +tok(parser_state *p) +{ + return p->buf; +} + +static int +toklen(parser_state *p) +{ + return p->bidx; +} + +#define IS_ARG() (p->lstate == EXPR_ARG || p->lstate == EXPR_CMDARG) +#define IS_END() (p->lstate == EXPR_END || p->lstate == EXPR_ENDARG || p->lstate == EXPR_ENDFN) +#define IS_BEG() (p->lstate == EXPR_BEG || p->lstate == EXPR_MID || p->lstate == EXPR_VALUE || p->lstate == EXPR_CLASS) +#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c)) +#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG()) +#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1)) + +static int +scan_oct(const int *start, int len, int *retlen) +{ + const int *s = start; + int retval = 0; + + /* mrb_assert(len <= 3) */ + while (len-- && *s >= '0' && *s <= '7') { + retval <<= 3; + retval |= *s++ - '0'; + } + *retlen = s - start; + + return retval; +} + +static int32_t +scan_hex(const int *start, int len, int *retlen) +{ + static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; + const int *s = start; + int32_t retval = 0; + char *tmp; + + /* mrb_assert(len <= 8) */ + while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { + retval <<= 4; + retval |= (tmp - hexdigit) & 15; + s++; + } + *retlen = s - start; + + return retval; +} + +/* Return negative to indicate Unicode code point */ +static int32_t +read_escape(parser_state *p) +{ + int32_t c; + + switch (c = nextc(p)) { + case '\\':/* Backslash */ + return c; + + case 'n':/* newline */ + return '\n'; + + case 't':/* horizontal tab */ + return '\t'; + + case 'r':/* carriage-return */ + return '\r'; + + case 'f':/* form-feed */ + return '\f'; + + case 'v':/* vertical tab */ + return '\13'; + + case 'a':/* alarm(bell) */ + return '\007'; + + case 'e':/* escape */ + return 033; + + case '0': case '1': case '2': case '3': /* octal constant */ + case '4': case '5': case '6': case '7': + { + int buf[3]; + int i; + + buf[0] = c; + for (i=1; i<3; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (buf[i] < '0' || '7' < buf[i]) { + pushback(p, buf[i]); + break; + } + } + c = scan_oct(buf, i, &i); + } + return c; + + case 'x': /* hex constant */ + { + int buf[2]; + int i; + + for (i=0; i<2; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + } + return c; + + case 'u': /* Unicode */ + { + int buf[9]; + int i; + + /* Look for opening brace */ + i = 0; + buf[0] = nextc(p); + if (buf[0] < 0) goto eof; + if (buf[0] == '{') { + /* \u{xxxxxxxx} form */ + for (i=0; i<9; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (buf[i] == '}') { + break; + } + else if (!ISXDIGIT(buf[i])) { + yyerror(p, "Invalid escape character syntax"); + pushback(p, buf[i]); + return 0; + } + } + } + else if (ISXDIGIT(buf[0])) { + /* \uxxxx form */ + for (i=1; i<4; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + } + else { + pushback(p, buf[0]); + } + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { + yyerror(p, "Invalid Unicode code point"); + return 0; + } + } + return -c; + + case 'b':/* backspace */ + return '\010'; + + case 's':/* space */ + return ' '; + + case 'M': + if ((c = nextc(p)) != '-') { + yyerror(p, "Invalid escape character syntax"); + pushback(p, c); + return '\0'; + } + if ((c = nextc(p)) == '\\') { + return read_escape(p) | 0x80; + } + else if (c < 0) goto eof; + else { + return ((c & 0xff) | 0x80); + } + + case 'C': + if ((c = nextc(p)) != '-') { + yyerror(p, "Invalid escape character syntax"); + pushback(p, c); + return '\0'; + } + case 'c': + if ((c = nextc(p))== '\\') { + c = read_escape(p); + } + else if (c == '?') + return 0177; + else if (c < 0) goto eof; + return c & 0x9f; + + eof: + case -1: + case -2: /* end of a file */ + yyerror(p, "Invalid escape character syntax"); + return '\0'; + + default: + return c; + } +} + +static int +parse_string(parser_state *p) +{ + int c; + string_type type = (string_type)(intptr_t)p->lex_strterm->car; + int nest_level = (intptr_t)p->lex_strterm->cdr->car; + int beg = (intptr_t)p->lex_strterm->cdr->cdr->car; + int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr; + parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL; + + newtok(p); + while ((c = nextc(p)) != end || nest_level != 0) { + if (hinf && (c == '\n' || c < 0)) { + mrb_bool line_head; + tokadd(p, '\n'); + tokfix(p); + p->lineno++; + p->column = 0; + line_head = hinf->line_head; + hinf->line_head = TRUE; + if (line_head) { + /* check whether end of heredoc */ + const char *s = tok(p); + int len = toklen(p); + if (hinf->allow_indent) { + while (ISSPACE(*s) && len > 0) { + ++s; + --len; + } + } + if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { + return tHEREDOC_END; + } + } + if (c < 0) { + char buf[256]; + snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + yyerror(p, buf); + return 0; + } + yylval.nd = new_str(p, tok(p), toklen(p)); + return tHD_STRING_MID; + } + if (c < 0) { + yyerror(p, "unterminated string meets end of file"); + return 0; + } + else if (c == beg) { + nest_level++; + p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + } + else if (c == end) { + nest_level--; + p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + } + else if (c == '\\') { + c = nextc(p); + if (type & STR_FUNC_EXPAND) { + if (c == end || c == beg) { + tokadd(p, c); + } + else if (c == '\n') { + p->lineno++; + p->column = 0; + if (type & STR_FUNC_ARRAY) { + tokadd(p, '\n'); + } + } + else if (type & STR_FUNC_REGEXP) { + tokadd(p, '\\'); + tokadd(p, c); + } + else { + pushback(p, c); + tokadd(p, read_escape(p)); + if (hinf) + hinf->line_head = FALSE; + } + } + else { + if (c != beg && c != end) { + if (c == '\n') { + p->lineno++; + p->column = 0; + } + if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) { + tokadd(p, '\\'); + } + } + tokadd(p, c); + } + continue; + } + else if ((c == '#') && (type & STR_FUNC_EXPAND)) { + c = nextc(p); + if (c == '{') { + tokfix(p); + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + yylval.nd = new_str(p, tok(p), toklen(p)); + if (hinf) { + hinf->line_head = FALSE; + return tHD_STRING_PART; + } + return tSTRING_PART; + } + tokadd(p, '#'); + pushback(p, c); + continue; + } + if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { + if (toklen(p) == 0) { + do { + if (c == '\n') { + p->lineno++; + p->column = 0; + heredoc_treat_nextline(p); + if (p->parsing_heredoc != NULL) { + return tHD_LITERAL_DELIM; + } + } + c = nextc(p); + } while (ISSPACE(c)); + pushback(p, c); + return tLITERAL_DELIM; + } + else { + pushback(p, c); + tokfix(p); + yylval.nd = new_str(p, tok(p), toklen(p)); + return tSTRING_MID; + } + } + tokadd(p, c); + } + + tokfix(p); + p->lstate = EXPR_END; + end_strterm(p); + + if (type & STR_FUNC_XQUOTE) { + yylval.nd = new_xstr(p, tok(p), toklen(p)); + return tXSTRING; + } + + if (type & STR_FUNC_REGEXP) { + int f = 0; + int re_opt; + char *s = strndup(tok(p), toklen(p)); + char flags[3]; + char *flag = flags; + char *dup; + + newtok(p); + while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) { + switch (re_opt) { + case 'i': f |= 1; break; + case 'x': f |= 2; break; + case 'm': f |= 4; break; + default: tokadd(p, re_opt); break; + } + } + pushback(p, re_opt); + if (toklen(p)) { + char msg[128]; + tokfix(p); + snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", + toklen(p) > 1 ? "s" : "", tok(p)); + yyerror(p, msg); + } + if (f != 0) { + if (f & 1) *flag++ = 'i'; + if (f & 2) *flag++ = 'x'; + if (f & 4) *flag++ = 'm'; + dup = strndup(flags, (size_t)(flag - flags)); + } + else { + dup = NULL; + } + yylval.nd = new_regx(p, s, dup); + + return tREGEXP; + } + + yylval.nd = new_str(p, tok(p), toklen(p)); + return tSTRING; +} + + +static int +heredoc_identifier(parser_state *p) +{ + int c; + int type = str_heredoc; + mrb_bool indent = FALSE; + mrb_bool quote = FALSE; + node *newnode; + parser_heredoc_info *info; + + c = nextc(p); + if (ISSPACE(c) || c == '=') { + pushback(p, c); + return 0; + } + if (c == '-') { + indent = TRUE; + c = nextc(p); + } + if (c == '\'' || c == '"') { + int term = c; + if (c == '\'') + quote = TRUE; + newtok(p); + while ((c = nextc(p)) >= 0 && c != term) { + if (c == '\n') { + c = -1; + break; + } + tokadd(p, c); + } + if (c < 0) { + yyerror(p, "unterminated here document identifier"); + return 0; + } + } + else { + if (c < 0) { + return 0; /* missing here document identifier */ + } + if (! identchar(c)) { + pushback(p, c); + if (indent) pushback(p, '-'); + return 0; + } + newtok(p); + do { + tokadd(p, c); + } while ((c = nextc(p)) >= 0 && identchar(c)); + pushback(p, c); + } + tokfix(p); + newnode = new_heredoc(p); + info = (parser_heredoc_info*)newnode->cdr; + info->term = strndup(tok(p), toklen(p)); + info->term_len = toklen(p); + if (! quote) + type |= STR_FUNC_EXPAND; + info->type = (string_type)type; + info->allow_indent = indent; + info->line_head = TRUE; + info->doc = NULL; + p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode); + p->lstate = EXPR_END; + + yylval.nd = newnode; + return tHEREDOC_BEG; +} + +static int +arg_ambiguous(parser_state *p) +{ + yywarning(p, "ambiguous first argument; put parentheses or even spaces"); + return 1; +} + +#include "lex.def" + +static int +parser_yylex(parser_state *p) +{ + int32_t c; + int space_seen = 0; + int cmd_state; + enum mrb_lex_state_enum last_state; + int token_column; + + if (p->lex_strterm) { + if (is_strterm_type(p, STR_FUNC_HEREDOC)) { + if (p->parsing_heredoc != NULL) + return parse_string(p); + } + else + return parse_string(p); + } + cmd_state = p->cmd_start; + p->cmd_start = FALSE; + retry: + last_state = p->lstate; + switch (c = nextc(p)) { + case '\004': /* ^D */ + case '\032': /* ^Z */ + case '\0': /* NUL */ + case -1: /* end of script. */ + if (p->heredocs_from_nextline) + goto maybe_heredoc; + return 0; + + /* white spaces */ + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + goto retry; + + case '#': /* it's a comment */ + skip(p, '\n'); + /* fall through */ + case -2: /* end of a file */ + case '\n': + maybe_heredoc: + heredoc_treat_nextline(p); + switch (p->lstate) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + case EXPR_CLASS: + case EXPR_VALUE: + p->lineno++; + p->column = 0; + if (p->parsing_heredoc != NULL) { + if (p->lex_strterm) { + return parse_string(p); + } + } + goto retry; + default: + break; + } + if (p->parsing_heredoc != NULL) { + return '\n'; + } + while ((c = nextc(p))) { + switch (c) { + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + break; + case '.': + if ((c = nextc(p)) != '.') { + pushback(p, c); + pushback(p, '.'); + goto retry; + } + case -1: /* EOF */ + case -2: /* end of a file */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; + } + } + normal_newline: + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; + + case '*': + if ((c = nextc(p)) == '*') { + if ((c = nextc(p)) == '=') { + yylval.id = intern("**",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + c = tPOW; + } + else { + if (c == '=') { + yylval.id = intern_c('*'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + yywarning(p, "`*' interpreted as argument prefix"); + c = tSTAR; + } + else if (IS_BEG()) { + c = tSTAR; + } + else { + c = '*'; + } + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return c; + + case '!': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return '!'; + } + } + else { + p->lstate = EXPR_BEG; + } + if (c == '=') { + return tNEQ; + } + if (c == '~') { + return tNMATCH; + } + pushback(p, c); + return '!'; + + case '=': + if (p->column == 1) { + static const char begin[] = "begin"; + static const char end[] = "\n=end"; + if (peeks(p, begin)) { + c = peekc_n(p, sizeof(begin)-1); + if (c < 0 || ISSPACE(c)) { + do { + if (!skips(p, end)) { + yyerror(p, "embedded document meets end of file"); + return 0; + } + c = nextc(p); + } while (!(c < 0 || ISSPACE(c))); + if (c != '\n') skip(p, '\n'); + p->lineno++; + p->column = 0; + goto retry; + } + } + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + if ((c = nextc(p)) == '=') { + if ((c = nextc(p)) == '=') { + return tEQQ; + } + pushback(p, c); + return tEQ; + } + if (c == '~') { + return tMATCH; + } + else if (c == '>') { + return tASSOC; + } + pushback(p, c); + return '='; + + case '<': + c = nextc(p); + if (c == '<' && + p->lstate != EXPR_DOT && + p->lstate != EXPR_CLASS && + !IS_END() && + (!IS_ARG() || space_seen)) { + int token = heredoc_identifier(p); + if (token) + return token; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + if (p->lstate == EXPR_CLASS) { + p->cmd_start = TRUE; + } + } + if (c == '=') { + if ((c = nextc(p)) == '>') { + return tCMP; + } + pushback(p, c); + return tLEQ; + } + if (c == '<') { + if ((c = nextc(p)) == '=') { + yylval.id = intern("<<",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tLSHFT; + } + pushback(p, c); + return '<'; + + case '>': + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + if ((c = nextc(p)) == '=') { + return tGEQ; + } + if (c == '>') { + if ((c = nextc(p)) == '=') { + yylval.id = intern(">>",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tRSHFT; + } + pushback(p, c); + return '>'; + + case '"': + p->lex_strterm = new_strterm(p, str_dquote, '"', 0); + return tSTRING_BEG; + + case '\'': + p->lex_strterm = new_strterm(p, str_squote, '\'', 0); + return parse_string(p); + + case '`': + if (p->lstate == EXPR_FNAME) { + p->lstate = EXPR_ENDFN; + return '`'; + } + if (p->lstate == EXPR_DOT) { + if (cmd_state) + p->lstate = EXPR_CMDARG; + else + p->lstate = EXPR_ARG; + return '`'; + } + p->lex_strterm = new_strterm(p, str_xquote, '`', 0); + return tXSTRING_BEG; + + case '?': + if (IS_END()) { + p->lstate = EXPR_VALUE; + return '?'; + } + c = nextc(p); + if (c < 0) { + yyerror(p, "incomplete character syntax"); + return 0; + } + if (ISSPACE(c)) { + if (!IS_ARG()) { + int c2; + switch (c) { + case ' ': + c2 = 's'; + break; + case '\n': + c2 = 'n'; + break; + case '\t': + c2 = 't'; + break; + case '\v': + c2 = 'v'; + break; + case '\r': + c2 = 'r'; + break; + case '\f': + c2 = 'f'; + break; + default: + c2 = 0; + break; + } + if (c2) { + char buf[256]; + snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + yyerror(p, buf); + } + } + ternary: + pushback(p, c); + p->lstate = EXPR_VALUE; + return '?'; + } + newtok(p); + /* need support UTF-8 if configured */ + if ((isalnum(c) || c == '_')) { + int c2 = nextc(p); + pushback(p, c2); + if ((isalnum(c2) || c2 == '_')) { + goto ternary; + } + } + if (c == '\\') { + c = read_escape(p); + tokadd(p, c); + } + else { + tokadd(p, c); + } + tokfix(p); + yylval.nd = new_str(p, tok(p), toklen(p)); + p->lstate = EXPR_END; + return tCHAR; + + case '&': + if ((c = nextc(p)) == '&') { + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '=') { + yylval.id = intern("&&",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tANDOP; + } + else if (c == '=') { + yylval.id = intern_c('&'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + yywarning(p, "`&' interpreted as argument prefix"); + c = tAMPER; + } + else if (IS_BEG()) { + c = tAMPER; + } + else { + c = '&'; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return c; + + case '|': + if ((c = nextc(p)) == '|') { + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '=') { + yylval.id = intern("||",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tOROP; + } + if (c == '=') { + yylval.id = intern_c('|'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '|'; + + case '+': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return tUPLUS; + } + pushback(p, c); + return '+'; + } + if (c == '=') { + yylval.id = intern_c('+'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { + p->lstate = EXPR_BEG; + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + c = '+'; + goto start_num; + } + return tUPLUS; + } + p->lstate = EXPR_BEG; + pushback(p, c); + return '+'; + + case '-': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return tUMINUS; + } + pushback(p, c); + return '-'; + } + if (c == '=') { + yylval.id = intern_c('-'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (c == '>') { + p->lstate = EXPR_ENDFN; + return tLAMBDA; + } + if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { + p->lstate = EXPR_BEG; + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + return tUMINUS_NUM; + } + return tUMINUS; + } + p->lstate = EXPR_BEG; + pushback(p, c); + return '-'; + + case '.': + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '.') { + if ((c = nextc(p)) == '.') { + return tDOT3; + } + pushback(p, c); + return tDOT2; + } + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + yyerror(p, "no . floating literal anymore; put 0 before dot"); + } + p->lstate = EXPR_DOT; + return '.'; + + start_num: + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int is_float, seen_point, seen_e, nondigit; + + is_float = seen_point = seen_e = nondigit = 0; + p->lstate = EXPR_END; + newtok(p); + if (c == '-' || c == '+') { + tokadd(p, c); + c = nextc(p); + } + if (c == '0') { +#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0) + int start = toklen(p); + c = nextc(p); + if (c == 'x' || c == 'X') { + /* hexadecimal */ + c = nextc(p); + if (c >= 0 && ISXDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISXDIGIT(c)) break; + nondigit = 0; + tokadd(p, tolower(c)); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 16); + return tINTEGER; + } + if (c == 'b' || c == 'B') { + /* binary */ + c = nextc(p); + if (c == '0' || c == '1') { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c != '0' && c != '1') break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 2); + return tINTEGER; + } + if (c == 'd' || c == 'D') { + /* decimal */ + c = nextc(p); + if (c >= 0 && ISDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISDIGIT(c)) break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } + if (c == '_') { + /* 0_0 */ + goto octal_number; + } + if (c == 'o' || c == 'O') { + /* prefixed octal */ + c = nextc(p); + if (c < 0 || c == '_' || !ISDIGIT(c)) { + no_digits(); + } + } + if (c >= '0' && c <= '7') { + /* octal */ + octal_number: + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c < '0' || c > '9') break; + if (c > '7') goto invalid_octal; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + + if (toklen(p) > start) { + pushback(p, c); + tokfix(p); + if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 8); + return tINTEGER; + } + if (nondigit) { + pushback(p, c); + goto trailing_uc; + } + } + if (c > '7' && c <= '9') { + invalid_octal: + yyerror(p, "Invalid octal digit"); + } + else if (c == '.' || c == 'e' || c == 'E') { + tokadd(p, '0'); + } + else { + pushback(p, c); + yylval.nd = new_int(p, "0", 10); + return tINTEGER; + } + } + + for (;;) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + nondigit = 0; + tokadd(p, c); + break; + + case '.': + if (nondigit) goto trailing_uc; + if (seen_point || seen_e) { + goto decode_num; + } + else { + int c0 = nextc(p); + if (c0 < 0 || !ISDIGIT(c0)) { + pushback(p, c0); + goto decode_num; + } + c = c0; + } + tokadd(p, '.'); + tokadd(p, c); + is_float++; + seen_point++; + nondigit = 0; + break; + + case 'e': + case 'E': + if (nondigit) { + pushback(p, c); + c = nondigit; + goto decode_num; + } + if (seen_e) { + goto decode_num; + } + tokadd(p, c); + seen_e++; + is_float++; + nondigit = c; + c = nextc(p); + if (c != '-' && c != '+') continue; + tokadd(p, c); + nondigit = c; + break; + + case '_': /* `_' in number just ignored */ + if (nondigit) goto decode_num; + nondigit = c; + break; + + default: + goto decode_num; + } + c = nextc(p); + } + + decode_num: + pushback(p, c); + if (nondigit) { + trailing_uc: + yyerror_i(p, "trailing `%c' in number", nondigit); + } + tokfix(p); + if (is_float) { + double d; + char *endp; + + errno = 0; + d = strtod(tok(p), &endp); + if (d == 0 && endp == tok(p)) { + yywarning_s(p, "corrupted float value %s", tok(p)); + } + else if (errno == ERANGE) { + yywarning_s(p, "float %s out of range", tok(p)); + errno = 0; + } + yylval.nd = new_float(p, tok(p)); + return tFLOAT; + } + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } + + case ')': + case ']': + p->paren_nest--; + case '}': + COND_LEXPOP(); + CMDARG_LEXPOP(); + if (c == ')') + p->lstate = EXPR_ENDFN; + else + p->lstate = EXPR_ENDARG; + return c; + + case ':': + c = nextc(p); + if (c == ':') { + if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { + p->lstate = EXPR_BEG; + return tCOLON3; + } + p->lstate = EXPR_DOT; + return tCOLON2; + } + if (IS_END() || ISSPACE(c)) { + pushback(p, c); + p->lstate = EXPR_BEG; + return ':'; + } + pushback(p, c); + p->lstate = EXPR_FNAME; + return tSYMBEG; + + case '/': + if (IS_BEG()) { + p->lex_strterm = new_strterm(p, str_regexp, '/', 0); + return tREGEXP_BEG; + } + if ((c = nextc(p)) == '=') { + yylval.id = intern_c('/'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + p->lex_strterm = new_strterm(p, str_regexp, '/', 0); + return tREGEXP_BEG; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return '/'; + + case '^': + if ((c = nextc(p)) == '=') { + yylval.id = intern_c('^'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '^'; + + case ';': + p->lstate = EXPR_BEG; + return ';'; + + case ',': + p->lstate = EXPR_BEG; + return ','; + + case '~': + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + if ((c = nextc(p)) != '@') { + pushback(p, c); + } + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return '~'; + + case '(': + if (IS_BEG()) { + c = tLPAREN; + } + else if (IS_SPCARG(-1)) { + c = tLPAREN_ARG; + } + p->paren_nest++; + COND_PUSH(0); + CMDARG_PUSH(0); + p->lstate = EXPR_BEG; + return c; + + case '[': + p->paren_nest++; + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if ((c = nextc(p)) == ']') { + if ((c = nextc(p)) == '=') { + return tASET; + } + pushback(p, c); + return tAREF; + } + pushback(p, c); + return '['; + } + else if (IS_BEG()) { + c = tLBRACK; + } + else if (IS_ARG() && space_seen) { + c = tLBRACK; + } + p->lstate = EXPR_BEG; + COND_PUSH(0); + CMDARG_PUSH(0); + return c; + + case '{': + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lstate = EXPR_BEG; + p->lpar_beg = 0; + p->paren_nest--; + COND_PUSH(0); + CMDARG_PUSH(0); + return tLAMBEG; + } + if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN) + c = '{'; /* block (primary) */ + else if (p->lstate == EXPR_ENDARG) + c = tLBRACE_ARG; /* block (expr) */ + else + c = tLBRACE; /* hash */ + COND_PUSH(0); + CMDARG_PUSH(0); + p->lstate = EXPR_BEG; + return c; + + case '\\': + c = nextc(p); + if (c == '\n') { + p->lineno++; + p->column = 0; + space_seen = 1; + goto retry; /* skip \\n */ + } + pushback(p, c); + return '\\'; + + case '%': + if (IS_BEG()) { + int term; + int paren; + + c = nextc(p); + quotation: + if (c < 0 || !ISALNUM(c)) { + term = c; + c = 'Q'; + } + else { + term = nextc(p); + if (isalnum(term)) { + yyerror(p, "unknown type of %string"); + return 0; + } + } + if (c < 0 || term < 0) { + yyerror(p, "unterminated quoted string meets end of file"); + return 0; + } + paren = term; + if (term == '(') term = ')'; + else if (term == '[') term = ']'; + else if (term == '{') term = '}'; + else if (term == '<') term = '>'; + else paren = 0; + + switch (c) { + case 'Q': + p->lex_strterm = new_strterm(p, str_dquote, term, paren); + return tSTRING_BEG; + + case 'q': + p->lex_strterm = new_strterm(p, str_squote, term, paren); + return parse_string(p); + + case 'W': + p->lex_strterm = new_strterm(p, str_dword, term, paren); + return tWORDS_BEG; + + case 'w': + p->lex_strterm = new_strterm(p, str_sword, term, paren); + return tWORDS_BEG; + + case 'x': + p->lex_strterm = new_strterm(p, str_xquote, term, paren); + return tXSTRING_BEG; + + case 'r': + p->lex_strterm = new_strterm(p, str_regexp, term, paren); + return tREGEXP_BEG; + + case 's': + p->lex_strterm = new_strterm(p, str_ssym, term, paren); + return tSYMBEG; + + case 'I': + p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); + return tSYMBOLS_BEG; + + case 'i': + p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); + return tSYMBOLS_BEG; + + default: + yyerror(p, "unknown type of %string"); + return 0; + } + } + if ((c = nextc(p)) == '=') { + yylval.id = intern_c('%'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (IS_SPCARG(c)) { + goto quotation; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '%'; + + case '$': + p->lstate = EXPR_END; + token_column = newtok(p); + c = nextc(p); + if (c < 0) { + yyerror(p, "incomplete global variable syntax"); + return 0; + } + switch (c) { + case '_': /* $_: last read line string */ + c = nextc(p); + if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ + tokadd(p, '$'); + tokadd(p, c); + break; + } + pushback(p, c); + c = '_'; + /* fall through */ + case '~': /* $~: match-data */ + case '*': /* $*: argv */ + case '$': /* $$: pid */ + case '?': /* $?: last status */ + case '!': /* $!: error string */ + case '@': /* $@: error position */ + case '/': /* $/: input record separator */ + case '\\': /* $\: output record separator */ + case ';': /* $;: field separator */ + case ',': /* $,: output field separator */ + case '.': /* $.: last read line number */ + case '=': /* $=: ignorecase */ + case ':': /* $:: load path */ + case '<': /* $<: reading filename */ + case '>': /* $>: default output handle */ + case '\"': /* $": already loaded files */ + tokadd(p, '$'); + tokadd(p, c); + tokfix(p); + yylval.id = intern_cstr(tok(p)); + return tGVAR; + + case '-': + tokadd(p, '$'); + tokadd(p, c); + c = nextc(p); + pushback(p, c); + gvar: + tokfix(p); + yylval.id = intern_cstr(tok(p)); + return tGVAR; + + case '&': /* $&: last match */ + case '`': /* $`: string before last match */ + case '\'': /* $': string after last match */ + case '+': /* $+: string matches last pattern */ + if (last_state == EXPR_FNAME) { + tokadd(p, '$'); + tokadd(p, c); + goto gvar; + } + yylval.nd = new_back_ref(p, c); + return tBACK_REF; + + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + do { + tokadd(p, c); + c = nextc(p); + } while (c >= 0 && isdigit(c)); + pushback(p, c); + if (last_state == EXPR_FNAME) goto gvar; + tokfix(p); + { + unsigned long n = strtoul(tok(p), NULL, 10); + if (n > INT_MAX) { + yyerror_i(p, "capture group index must be <= %d", INT_MAX); + return 0; + } + yylval.nd = new_nth_ref(p, (int)n); + } + return tNTH_REF; + + default: + if (!identchar(c)) { + pushback(p, c); + return '$'; + } + case '0': + tokadd(p, '$'); + } + break; + + case '@': + c = nextc(p); + token_column = newtok(p); + tokadd(p, '@'); + if (c == '@') { + tokadd(p, '@'); + c = nextc(p); + } + if (c < 0) { + if (p->bidx == 1) { + yyerror(p, "incomplete instance variable syntax"); + } + else { + yyerror(p, "incomplete class variable syntax"); + } + return 0; + } + else if (isdigit(c)) { + if (p->bidx == 1) { + yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + } + else { + yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + } + return 0; + } + if (!identchar(c)) { + pushback(p, c); + return '@'; + } + break; + + case '_': + token_column = newtok(p); + break; + + default: + if (!identchar(c)) { + yyerror_i(p, "Invalid char `\\x%02X' in expression", c); + goto retry; + } + + token_column = newtok(p); + break; + } + + do { + tokadd(p, c); + c = nextc(p); + if (c < 0) break; + } while (identchar(c)); + if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') && + strncmp(tok(p), "__END__", toklen(p)) == 0) + return -1; + + switch (tok(p)[0]) { + case '@': case '$': + pushback(p, c); + break; + default: + if ((c == '!' || c == '?') && !peek(p, '=')) { + tokadd(p, c); + } + else { + pushback(p, c); + } + } + tokfix(p); + { + int result = 0; + + switch (tok(p)[0]) { + case '$': + p->lstate = EXPR_END; + result = tGVAR; + break; + case '@': + p->lstate = EXPR_END; + if (tok(p)[1] == '@') + result = tCVAR; + else + result = tIVAR; + break; + + default: + if (toklast(p) == '!' || toklast(p) == '?') { + result = tFID; + } + else { + if (p->lstate == EXPR_FNAME) { + if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && + (!peek(p, '=') || (peek_n(p, '>', 1)))) { + result = tIDENTIFIER; + tokadd(p, c); + tokfix(p); + } + else { + pushback(p, c); + } + } + if (result == 0 && ISUPPER(tok(p)[0])) { + result = tCONSTANT; + } + else { + result = tIDENTIFIER; + } + } + + if (IS_LABEL_POSSIBLE()) { + if (IS_LABEL_SUFFIX(0)) { + p->lstate = EXPR_BEG; + nextc(p); + tokfix(p); + yylval.id = intern_cstr(tok(p)); + return tLABEL; + } + } + if (p->lstate != EXPR_DOT) { + const struct kwtable *kw; + + /* See if it is a reserved word. */ + kw = mrb_reserved_word(tok(p), toklen(p)); + if (kw) { + enum mrb_lex_state_enum state = p->lstate; + yylval.num = p->lineno; + p->lstate = kw->state; + if (state == EXPR_FNAME) { + yylval.id = intern_cstr(kw->name); + return kw->id[0]; + } + if (p->lstate == EXPR_BEG) { + p->cmd_start = TRUE; + } + if (kw->id[0] == keyword_do) { + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lpar_beg = 0; + p->paren_nest--; + return keyword_do_LAMBDA; + } + if (COND_P()) return keyword_do_cond; + if (CMDARG_P() && state != EXPR_CMDARG) + return keyword_do_block; + if (state == EXPR_ENDARG || state == EXPR_BEG) + return keyword_do_block; + return keyword_do; + } + if (state == EXPR_BEG || state == EXPR_VALUE) + return kw->id[0]; + else { + if (kw->id[0] != kw->id[1]) + p->lstate = EXPR_BEG; + return kw->id[1]; + } + } + } + + if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) { + if (cmd_state) { + p->lstate = EXPR_CMDARG; + } + else { + p->lstate = EXPR_ARG; + } + } + else if (p->lstate == EXPR_FNAME) { + p->lstate = EXPR_ENDFN; + } + else { + p->lstate = EXPR_END; + } + } + { + mrb_sym ident = intern_cstr(tok(p)); + + yylval.id = ident; +#if 0 + if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) { + p->lstate = EXPR_END; + } +#endif + } + return result; + } +} + +static int +yylex(void *lval, parser_state *p) +{ + p->ylval = lval; + return parser_yylex(p); +} + +static void +parser_init_cxt(parser_state *p, mrbc_context *cxt) +{ + if (!cxt) return; + if (cxt->filename) mrb_parser_set_filename(p, cxt->filename); + if (cxt->lineno) p->lineno = cxt->lineno; + if (cxt->syms) { + int i; + + p->locals = cons(0,0); + for (i=0; islen; i++) { + local_add_f(p, cxt->syms[i]); + } + } + p->capture_errors = cxt->capture_errors; + p->no_optimize = cxt->no_optimize; + if (cxt->partial_hook) { + p->cxt = cxt; + } +} + +static void +parser_update_cxt(parser_state *p, mrbc_context *cxt) +{ + node *n, *n0; + int i = 0; + + if (!cxt) return; + if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; + n0 = n = p->tree->cdr->car; + while (n) { + i++; + n = n->cdr; + } + cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym)); + cxt->slen = i; + for (i=0, n=n0; n; i++,n=n->cdr) { + cxt->syms[i] = sym(n->car); + } +} + +void mrb_codedump_all(mrb_state*, struct RProc*); +void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); + +MRB_API void +mrb_parser_parse(parser_state *p, mrbc_context *c) +{ + struct mrb_jmpbuf buf; + p->jmp = &buf; + + MRB_TRY(p->jmp) { + + p->cmd_start = TRUE; + p->in_def = p->in_single = 0; + p->nerr = p->nwarn = 0; + p->lex_strterm = NULL; + + parser_init_cxt(p, c); + yyparse(p); + if (!p->tree) { + p->tree = new_nil(p); + } + parser_update_cxt(p, c); + if (c && c->dump_result) { + mrb_parser_dump(p->mrb, p->tree, 0); + } + + } + MRB_CATCH(p->jmp) { + yyerror(p, "memory allocation error"); + p->nerr++; + p->tree = 0; + return; + } + MRB_END_EXC(p->jmp); +} + +MRB_API parser_state* +mrb_parser_new(mrb_state *mrb) +{ + mrb_pool *pool; + parser_state *p; + static const parser_state parser_state_zero = { 0 }; + + pool = mrb_pool_open(mrb); + if (!pool) return NULL; + p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state)); + if (!p) return NULL; + + *p = parser_state_zero; + p->mrb = mrb; + p->pool = pool; + + p->s = p->send = NULL; +#ifdef ENABLE_STDIO + p->f = NULL; +#endif + + p->cmd_start = TRUE; + p->in_def = p->in_single = 0; + + p->capture_errors = FALSE; + p->lineno = 1; + p->column = 0; +#if defined(PARSER_TEST) || defined(PARSER_DEBUG) + yydebug = 1; +#endif + + p->lex_strterm = NULL; + p->all_heredocs = p->parsing_heredoc = NULL; + p->lex_strterm_before_heredoc = NULL; + + p->current_filename_index = -1; + p->filename_table = NULL; + p->filename_table_length = 0; + + return p; +} + +MRB_API void +mrb_parser_free(parser_state *p) { + mrb_pool_close(p->pool); +} + +MRB_API mrbc_context* +mrbc_context_new(mrb_state *mrb) +{ + return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); +} + +MRB_API void +mrbc_context_free(mrb_state *mrb, mrbc_context *cxt) +{ + mrb_free(mrb, cxt->syms); + mrb_free(mrb, cxt); +} + +MRB_API const char* +mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) +{ + if (s) { + int len = strlen(s); + char *p = (char *)mrb_alloca(mrb, len + 1); + + memcpy(p, s, len + 1); + c->filename = p; + } + return c->filename; +} + +MRB_API void +mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data) +{ + c->partial_hook = func; + c->partial_data = data; +} + +MRB_API void +mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) +{ + mrb_sym sym; + size_t i; + mrb_sym* new_table; + + sym = mrb_intern_cstr(p->mrb, f); + p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->lineno = (p->filename_table_length > 0)? 0 : 1; + + for (i = 0; i < p->filename_table_length; ++i) { + if (p->filename_table[i] == sym) { + p->current_filename_index = i; + return; + } + } + + p->current_filename_index = p->filename_table_length++; + + new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); + if (p->filename_table) { + memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length); + } + p->filename_table = new_table; + p->filename_table[p->filename_table_length - 1] = sym; +} + +MRB_API char const* +mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { + if (idx >= p->filename_table_length) { return NULL; } + else { + return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + } +} + +#ifdef ENABLE_STDIO +MRB_API parser_state* +mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) +{ + parser_state *p; + + p = mrb_parser_new(mrb); + if (!p) return NULL; + p->s = p->send = NULL; + p->f = f; + + mrb_parser_parse(p, c); + return p; +} +#endif + +MRB_API parser_state* +mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c) +{ + parser_state *p; + + p = mrb_parser_new(mrb); + if (!p) return NULL; + p->s = s; + p->send = s + len; + + mrb_parser_parse(p, c); + return p; +} + +MRB_API parser_state* +mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c) +{ + return mrb_parse_nstring(mrb, s, strlen(s), c); +} + +static mrb_value +load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) +{ + struct RClass *target = mrb->object_class; + struct RProc *proc; + mrb_value v; + unsigned int keep = 0; + + if (!p) { + return mrb_undef_value(); + } + if (!p->tree || p->nerr) { + if (p->capture_errors) { + char buf[256]; + int n; + + n = snprintf(buf, sizeof(buf), "line %d: %s\n", + p->error_buffer[0].lineno, p->error_buffer[0].message); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + mrb_parser_free(p); + return mrb_undef_value(); + } + else { + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error")); + mrb_parser_free(p); + return mrb_undef_value(); + } + } + proc = mrb_generate_code(mrb, p); + mrb_parser_free(p); + if (proc == NULL) { + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error")); + return mrb_undef_value(); + } + if (c) { + if (c->dump_result) mrb_codedump_all(mrb, proc); + if (c->no_exec) return mrb_obj_value(proc); + if (c->target_class) { + target = c->target_class; + } + if (c->keep_lv) { + keep = c->slen + 1; + } + else { + c->keep_lv = TRUE; + } + } + proc->target_class = target; + if (mrb->c->ci) { + mrb->c->ci->target_class = target; + } + v = mrb_toplevel_run_keep(mrb, proc, keep); + if (mrb->exc) return mrb_nil_value(); + return v; +} + +#ifdef ENABLE_STDIO +MRB_API mrb_value +mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c) +{ + return load_exec(mrb, mrb_parse_file(mrb, f, c), c); +} + +MRB_API mrb_value +mrb_load_file(mrb_state *mrb, FILE *f) +{ + return mrb_load_file_cxt(mrb, f, NULL); +} +#endif + +MRB_API mrb_value +mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c) +{ + return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c); +} + +MRB_API mrb_value +mrb_load_nstring(mrb_state *mrb, const char *s, int len) +{ + return mrb_load_nstring_cxt(mrb, s, len, NULL); +} + +MRB_API mrb_value +mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c) +{ + return mrb_load_nstring_cxt(mrb, s, strlen(s), c); +} + +MRB_API mrb_value +mrb_load_string(mrb_state *mrb, const char *s) +{ + return mrb_load_string_cxt(mrb, s, NULL); +} + +#ifdef ENABLE_STDIO + +static void +dump_prefix(node *tree, int offset) +{ + printf("%05d ", tree->lineno); + while (offset--) { + putc(' ', stdout); + putc(' ', stdout); + } +} + +static void +dump_recur(mrb_state *mrb, node *tree, int offset) +{ + while (tree) { + mrb_parser_dump(mrb, tree->car, offset); + tree = tree->cdr; + } +} + +#endif + +void +mrb_parser_dump(mrb_state *mrb, node *tree, int offset) +{ +#ifdef ENABLE_STDIO + int nodetype; + + if (!tree) return; + again: + dump_prefix(tree, offset); + nodetype = (int)(intptr_t)tree->car; + tree = tree->cdr; + switch (nodetype) { + case NODE_BEGIN: + printf("NODE_BEGIN:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_RESCUE: + printf("NODE_RESCUE:\n"); + if (tree->car) { + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + } + tree = tree->cdr; + if (tree->car) { + node *n2 = tree->car; + + dump_prefix(n2, offset+1); + printf("rescue:\n"); + while (n2) { + node *n3 = n2->car; + if (n3->car) { + dump_prefix(n2, offset+2); + printf("handle classes:\n"); + dump_recur(mrb, n3->car, offset+3); + } + if (n3->cdr->car) { + dump_prefix(n3, offset+2); + printf("exc_var:\n"); + mrb_parser_dump(mrb, n3->cdr->car, offset+3); + } + if (n3->cdr->cdr->car) { + dump_prefix(n3, offset+2); + printf("rescue body:\n"); + mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); + } + n2 = n2->cdr; + } + } + tree = tree->cdr; + if (tree->car) { + dump_prefix(tree, offset+1); + printf("else:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + } + break; + + case NODE_ENSURE: + printf("NODE_ENSURE:\n"); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("ensure:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); + break; + + case NODE_LAMBDA: + printf("NODE_BLOCK:\n"); + goto block; + + case NODE_BLOCK: + block: + printf("NODE_BLOCK:\n"); + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + break; + + case NODE_IF: + printf("NODE_IF:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("then:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + if (tree->cdr->cdr->car) { + dump_prefix(tree, offset+1); + printf("else:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); + } + break; + + case NODE_AND: + printf("NODE_AND:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_OR: + printf("NODE_OR:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_CASE: + printf("NODE_CASE:\n"); + if (tree->car) { + mrb_parser_dump(mrb, tree->car, offset+1); + } + tree = tree->cdr; + while (tree) { + dump_prefix(tree, offset+1); + printf("case:\n"); + dump_recur(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + + case NODE_WHILE: + printf("NODE_WHILE:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_UNTIL: + printf("NODE_UNTIL:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_FOR: + printf("NODE_FOR:\n"); + dump_prefix(tree, offset+1); + printf("var:\n"); + { + node *n2 = tree->car; + + if (n2->car) { + dump_prefix(n2, offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("rest:\n"); + mrb_parser_dump(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } + } + } + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("in:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("do:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + break; + + case NODE_SCOPE: + printf("NODE_SCOPE:\n"); + { + node *n2 = tree->car; + mrb_bool first_lval = TRUE; + + if (n2 && (n2->car || n2->cdr)) { + dump_prefix(n2, offset+1); + printf("local variables:\n"); + dump_prefix(n2, offset+2); + while (n2) { + if (n2->car) { + if (!first_lval) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + first_lval = FALSE; + } + n2 = n2->cdr; + } + printf("\n"); + } + } + tree = tree->cdr; + offset++; + goto again; + + case NODE_FCALL: + case NODE_CALL: + printf("NODE_CALL:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("method='%s' (%d)\n", + mrb_sym2name(mrb, sym(tree->cdr->car)), + (int)(intptr_t)tree->cdr->car); + tree = tree->cdr->cdr->car; + if (tree) { + dump_prefix(tree, offset+1); + printf("args:\n"); + dump_recur(mrb, tree->car, offset+2); + if (tree->cdr) { + dump_prefix(tree, offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + } + } + break; + + case NODE_DOT2: + printf("NODE_DOT2:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_DOT3: + printf("NODE_DOT3:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_COLON2: + printf("NODE_COLON2:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); + break; + + case NODE_COLON3: + printf("NODE_COLON3:\n"); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_ARRAY: + printf("NODE_ARRAY:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_HASH: + printf("NODE_HASH:\n"); + while (tree) { + dump_prefix(tree, offset+1); + printf("key:\n"); + mrb_parser_dump(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("value:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + + case NODE_SPLAT: + printf("NODE_SPLAT:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_ASGN: + printf("NODE_ASGN:\n"); + dump_prefix(tree, offset+1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_MASGN: + printf("NODE_MASGN:\n"); + dump_prefix(tree, offset+1); + printf("mlhs:\n"); + { + node *n2 = tree->car; + + if (n2->car) { + dump_prefix(tree, offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("rest:\n"); + if (n2->car == (node*)-1) { + dump_prefix(n2, offset+2); + printf("(empty)\n"); + } + else { + mrb_parser_dump(mrb, n2->car, offset+3); + } + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } + } + } + dump_prefix(tree, offset+1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_OP_ASGN: + printf("NODE_OP_ASGN:\n"); + dump_prefix(tree, offset+1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); + tree = tree->cdr; + mrb_parser_dump(mrb, tree->car, offset+1); + break; + + case NODE_SUPER: + printf("NODE_SUPER:\n"); + if (tree) { + dump_prefix(tree, offset+1); + printf("args:\n"); + dump_recur(mrb, tree->car, offset+2); + if (tree->cdr) { + dump_prefix(tree, offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + } + } + break; + + case NODE_ZSUPER: + printf("NODE_ZSUPER\n"); + break; + + case NODE_RETURN: + printf("NODE_RETURN:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_YIELD: + printf("NODE_YIELD:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_BREAK: + printf("NODE_BREAK:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_NEXT: + printf("NODE_NEXT:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_REDO: + printf("NODE_REDO\n"); + break; + + case NODE_RETRY: + printf("NODE_RETRY\n"); + break; + + case NODE_LVAR: + printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_GVAR: + printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_IVAR: + printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_CVAR: + printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_CONST: + printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_MATCH: + printf("NODE_MATCH:\n"); + dump_prefix(tree, offset + 1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset + 2); + dump_prefix(tree, offset + 1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset + 2); + break; + + case NODE_BACK_REF: + printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); + break; + + case NODE_NTH_REF: + printf("NODE_NTH_REF: $%d\n", (int)(intptr_t)tree); + break; + + case NODE_ARG: + printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_BLOCK_ARG: + printf("NODE_BLOCK_ARG:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_INT: + printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); + break; + + case NODE_FLOAT: + printf("NODE_FLOAT %s\n", (char*)tree); + break; + + case NODE_NEGATE: + printf("NODE_NEGATE\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_STR: + printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + break; + + case NODE_DSTR: + printf("NODE_DSTR\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_XSTR: + printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + break; + + case NODE_DXSTR: + printf("NODE_DXSTR\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_REGX: + printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr); + break; + + case NODE_DREGX: + printf("NODE_DREGX\n"); + dump_recur(mrb, tree->car, offset+1); + dump_prefix(tree, offset); + printf("tail: %s\n", (char*)tree->cdr->cdr->car); + dump_prefix(tree, offset); + printf("opt: %s\n", (char*)tree->cdr->cdr->cdr); + break; + + case NODE_SYM: + printf("NODE_SYM :%s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_SELF: + printf("NODE_SELF\n"); + break; + + case NODE_NIL: + printf("NODE_NIL\n"); + break; + + case NODE_TRUE: + printf("NODE_TRUE\n"); + break; + + case NODE_FALSE: + printf("NODE_FALSE\n"); + break; + + case NODE_ALIAS: + printf("NODE_ALIAS %s %s:\n", + mrb_sym2name(mrb, sym(tree->car)), + mrb_sym2name(mrb, sym(tree->cdr))); + break; + + case NODE_UNDEF: + printf("NODE_UNDEF"); + { + node *t = tree; + while (t) { + printf(" %s", mrb_sym2name(mrb, sym(t->car))); + t = t->cdr; + } + } + printf(":\n"); + break; + + case NODE_CLASS: + printf("NODE_CLASS:\n"); + if (tree->car->car == (node*)0) { + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else if (tree->car->car == (node*)1) { + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else { + mrb_parser_dump(mrb, tree->car->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + if (tree->cdr->car) { + dump_prefix(tree, offset+1); + printf("super:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); + break; + + case NODE_MODULE: + printf("NODE_MODULE:\n"); + if (tree->car->car == (node*)0) { + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else if (tree->car->car == (node*)1) { + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else { + mrb_parser_dump(mrb, tree->car->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); + break; + + case NODE_SCLASS: + printf("NODE_SCLASS:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); + break; + + case NODE_DEF: + printf("NODE_DEF:\n"); + dump_prefix(tree, offset+1); + printf("%s\n", mrb_sym2name(mrb, sym(tree->car))); + tree = tree->cdr; + { + node *n2 = tree->car; + mrb_bool first_lval = TRUE; + + if (n2 && (n2->car || n2->cdr)) { + dump_prefix(n2, offset+1); + printf("local variables:\n"); + dump_prefix(n2, offset+2); + while (n2) { + if (n2->car) { + if (!first_lval) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + first_lval = FALSE; + } + n2 = n2->cdr; + } + printf("\n"); + } + } + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + if (n->cdr) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); + } + } + mrb_parser_dump(mrb, tree->cdr->car, offset+1); + break; + + case NODE_SDEF: + printf("NODE_SDEF:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); + tree = tree->cdr->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } + } + tree = tree->cdr; + mrb_parser_dump(mrb, tree->car, offset+1); + break; + + case NODE_POSTEXE: + printf("NODE_POSTEXE:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_HEREDOC: + printf("NODE_HEREDOC:\n"); + mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); + break; + + default: + printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); + break; + } +#endif +} diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake new file mode 100644 index 000000000..3a22762fa --- /dev/null +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -0,0 +1,40 @@ +MRuby::Gem::Specification.new 'mruby-compiler' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler library' + + current_dir = spec.dir + current_build_dir = spec.build_dir + + lex_def = "#{current_dir}/core/lex.def" + core_objs = Dir.glob("#{current_dir}/core/*.c").map { |f| + next nil if build.cxx_abi_enabled? and f =~ /(codegen).c$/ + objfile(f.pathmap("#{current_build_dir}/core/%n")) + }.compact + + if build.cxx_abi_enabled? + core_objs << + build.compile_as_cxx("#{current_build_dir}/core/y.tab.c", "#{current_build_dir}/core/y.tab.cxx", + objfile("#{current_build_dir}/y.tab"), ["#{current_dir}/core"]) << + build.compile_as_cxx("#{current_dir}/core/codegen.c", "#{current_build_dir}/core/codegen.cxx") + else + core_objs << objfile("#{current_build_dir}/core/y.tab") + file objfile("#{current_build_dir}/core/y.tab") => "#{current_build_dir}/core/y.tab.c" do |t| + cc.run t.name, t.prerequisites.first, [], ["#{current_dir}/core"] + end + end + file objfile("#{current_build_dir}/core/y.tab") => lex_def + + # Parser + file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t| + yacc.run t.name, t.prerequisites.first + end + + # Lexical analyzer + file lex_def => "#{current_dir}/core/keywords" do |t| + gperf.run t.name, t.prerequisites.first + end + + file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs + build.libmruby << core_objs +end diff --git a/mrbgems/mruby-eval/mrbgem.rake b/mrbgems/mruby-eval/mrbgem.rake index 7c6acc534..cb8835b32 100644 --- a/mrbgems/mruby-eval/mrbgem.rake +++ b/mrbgems/mruby-eval/mrbgem.rake @@ -2,4 +2,6 @@ MRuby::Gem::Specification.new('mruby-eval') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'standard Kernel#eval method' + + add_dependency 'mruby-compiler', :core => 'mruby-compiler' end diff --git a/src/codegen.c b/src/codegen.c deleted file mode 100644 index 16233347c..000000000 --- a/src/codegen.c +++ /dev/null @@ -1,2720 +0,0 @@ -/* -** codegen.c - mruby code generator -** -** See Copyright Notice in mruby.h -*/ - -#include -#include -#include -#include -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/proc.h" -#include "mruby/numeric.h" -#include "mruby/string.h" -#include "mruby/debug.h" -#include "node.h" -#include "mruby/opcode.h" -#include "mruby/re.h" -#include "mruby/throw.h" - -typedef mrb_ast_node node; -typedef struct mrb_parser_state parser_state; - -enum looptype { - LOOP_NORMAL, - LOOP_BLOCK, - LOOP_FOR, - LOOP_BEGIN, - LOOP_RESCUE, -}; - -struct loopinfo { - enum looptype type; - int pc1, pc2, pc3, acc; - int ensure_level; - struct loopinfo *prev; -}; - -typedef struct scope { - mrb_state *mrb; - mrb_pool *mpool; - struct mrb_jmpbuf jmp; - - struct scope *prev; - - node *lv; - - int sp; - int pc; - int lastlabel; - int ainfo:15; - mrb_bool mscope:1; - - struct loopinfo *loop; - int ensure_level; - char const *filename; - uint16_t lineno; - - mrb_code *iseq; - uint16_t *lines; - int icapa; - - mrb_irep *irep; - size_t pcapa; - size_t scapa; - size_t rcapa; - - uint16_t nlocals; - uint16_t nregs; - int ai; - - int debug_start_pos; - uint16_t filename_index; - parser_state* parser; -} codegen_scope; - -static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv); -static void scope_finish(codegen_scope *s); -static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); -static void loop_break(codegen_scope *s, node *tree); -static void loop_pop(codegen_scope *s, int val); - -static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); -static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); - -static void codegen(codegen_scope *s, node *tree, int val); -static void raise_error(codegen_scope *s, const char *msg); - -static void -codegen_error(codegen_scope *s, const char *message) -{ - if (!s) return; - while (s->prev) { - codegen_scope *tmp = s->prev; - mrb_pool_close(s->mpool); - s = tmp; - } -#ifdef ENABLE_STDIO - if (s->filename && s->lineno) { - fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); - } - else { - fprintf(stderr, "codegen error: %s\n", message); - } -#endif - MRB_THROW(&s->jmp); -} - -static void* -codegen_palloc(codegen_scope *s, size_t len) -{ - void *p = mrb_pool_alloc(s->mpool, len); - - if (!p) codegen_error(s, "pool memory allocation"); - return p; -} - -static void* -codegen_malloc(codegen_scope *s, size_t len) -{ - void *p = mrb_malloc_simple(s->mrb, len); - - if (!p) codegen_error(s, "mrb_malloc"); - return p; -} - -static void* -codegen_realloc(codegen_scope *s, void *p, size_t len) -{ - p = mrb_realloc_simple(s->mrb, p, len); - - if (!p && len > 0) codegen_error(s, "mrb_realloc"); - return p; -} - -static int -new_label(codegen_scope *s) -{ - s->lastlabel = s->pc; - return s->pc; -} - -static inline int -genop(codegen_scope *s, mrb_code i) -{ - if (s->pc == s->icapa) { - s->icapa *= 2; - s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); - if (s->lines) { - s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); - s->irep->lines = s->lines; - } - } - s->iseq[s->pc] = i; - if (s->lines) { - s->lines[s->pc] = s->lineno; - } - return s->pc++; -} - -#define NOVAL 0 -#define VAL 1 - -static mrb_bool -no_optimize(codegen_scope *s) -{ - if (s && s->parser && s->parser->no_optimize) - return TRUE; - return FALSE; -} - -static int -genop_peep(codegen_scope *s, mrb_code i, int val) -{ - /* peephole optimization */ - if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { - mrb_code i0 = s->iseq[s->pc-1]; - int c1 = GET_OPCODE(i); - int c0 = GET_OPCODE(i0); - - switch (c1) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_B(i)) { - /* skip useless OP_MOVE */ - return 0; - } - if (val) break; - switch (c0) { - case OP_MOVE: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { - /* skip swapping OP_MOVE */ - return 0; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->pc--; - return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); - } - break; - case OP_LOADI: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); - return 0; - } - break; - case OP_ARRAY: - case OP_HASH: - case OP_RANGE: - case OP_AREF: - case OP_GETUPVAR: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); - return 0; - } - break; - case OP_LOADSYM: - case OP_GETGLOBAL: - case OP_GETIV: - case OP_GETCV: - case OP_GETCONST: - case OP_GETSPECIAL: - case OP_LOADL: - case OP_STRING: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); - return 0; - } - break; - case OP_SCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_LOADNIL: - case OP_LOADSELF: - case OP_LOADT: - case OP_LOADF: - case OP_OCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); - return 0; - } - break; - default: - break; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETGLOBAL: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); - return 0; - } - } - break; - case OP_SETUPVAR: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); - return 0; - } - } - break; - case OP_EPOP: - if (c0 == OP_EPOP) { - s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_POPERR: - if (c0 == OP_POPERR) { - s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_RETURN: - switch (c0) { - case OP_RETURN: - return 0; - case OP_MOVE: - if (GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); - return 0; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETUPVAR: - case OP_SETGLOBAL: - s->pc--; - genop_peep(s, i0, NOVAL); - i0 = s->iseq[s->pc-1]; - return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); -#if 0 - case OP_SEND: - if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); - return; - } - break; -#endif - default: - break; - } - break; - case OP_ADD: - case OP_SUB: - if (c0 == OP_LOADI) { - int c = GETARG_sBx(i0); - - if (c1 == OP_SUB) c = -c; - if (c > 127 || c < -127) break; - if (0 <= c) - s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); - else - s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); - return 0; - } - case OP_STRCAT: - if (c0 == OP_STRING) { - mrb_value v = s->irep->pool[GETARG_Bx(i0)]; - - if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { - s->pc--; - return 0; - } - } - break; - case OP_JMPIF: - case OP_JMPNOT: - if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); - return s->pc-1; - } - break; - default: - break; - } - } - return genop(s, i); -} - -static void -scope_error(codegen_scope *s) -{ - exit(EXIT_FAILURE); -} - -static inline void -dispatch(codegen_scope *s, int pc) -{ - int diff = s->pc - pc; - mrb_code i = s->iseq[pc]; - int c = GET_OPCODE(i); - - s->lastlabel = s->pc; - switch (c) { - case OP_JMP: - case OP_JMPIF: - case OP_JMPNOT: - case OP_ONERR: - break; - default: -#ifdef ENABLE_STDIO - fprintf(stderr, "bug: dispatch on non JMP op\n"); -#endif - scope_error(s); - break; - } - s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); -} - -static void -dispatch_linked(codegen_scope *s, int pc) -{ - mrb_code i; - int pos; - - if (!pc) return; - for (;;) { - i = s->iseq[pc]; - pos = GETARG_sBx(i); - dispatch(s, pc); - if (!pos) break; - pc = pos; - } -} - -#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) -static void -push_(codegen_scope *s) -{ - if (s->sp > 511) { - codegen_error(s, "too complex expression"); - } - s->sp++; - nregs_update; -} - -#define push() push_(s) -#define pop_(s) ((s)->sp--) -#define pop() pop_(s) -#define pop_n(n) (s->sp-=(n)) -#define cursp() (s->sp) - -static inline int -new_lit(codegen_scope *s, mrb_value val) -{ - size_t i; - mrb_value *pv; - - switch (mrb_type(val)) { - case MRB_TT_STRING: - for (i=0; iirep->plen; i++) { - mrb_int len; - pv = &s->irep->pool[i]; - - if (mrb_type(*pv) != MRB_TT_STRING) continue; - if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue; - if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0) - return i; - } - break; - case MRB_TT_FLOAT: - for (i=0; iirep->plen; i++) { - pv = &s->irep->pool[i]; - if (mrb_type(*pv) != MRB_TT_FLOAT) continue; - if (mrb_float(*pv) == mrb_float(val)) return i; - } - break; - case MRB_TT_FIXNUM: - for (i=0; iirep->plen; i++) { - pv = &s->irep->pool[i]; - if (!mrb_fixnum_p(*pv)) continue; - if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i; - } - break; - default: - /* should not happen */ - return 0; - } - - if (s->irep->plen == s->pcapa) { - s->pcapa *= 2; - s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa); - } - - pv = &s->irep->pool[s->irep->plen]; - i = s->irep->plen++; - - switch (mrb_type(val)) { - case MRB_TT_STRING: - *pv = mrb_str_pool(s->mrb, val); - break; - - case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - *pv = mrb_float_pool(s->mrb, mrb_float(val)); - break; -#endif - case MRB_TT_FIXNUM: - *pv = val; - break; - - default: - /* should not happen */ - break; - } - return i; -} - -static inline int -new_msym(codegen_scope *s, mrb_sym sym) -{ - size_t i, len; - - mrb_assert(s->irep); - - len = s->irep->slen; - if (len > 256) len = 256; - for (i=0; iirep->syms[i] == sym) return i; - if (s->irep->syms[i] == 0) break; - } - if (i == 256) { - codegen_error(s, "too many symbols (max 256)"); - } - s->irep->syms[i] = sym; - if (i == s->irep->slen) s->irep->slen++; - return i; -} - -static inline int -new_sym(codegen_scope *s, mrb_sym sym) -{ - size_t i; - - for (i=0; iirep->slen; i++) { - if (s->irep->syms[i] == sym) return i; - } - if (s->irep->slen > 125 && s->irep->slen < 256) { - s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536); - for (i = 0; i < 256 - s->irep->slen; i++) { - static const mrb_sym mrb_sym_zero = { 0 }; - s->irep->syms[i + s->irep->slen] = mrb_sym_zero; - } - s->irep->slen = 256; - } - s->irep->syms[s->irep->slen] = sym; - return s->irep->slen++; -} - -static int -node_len(node *tree) -{ - int n = 0; - - while (tree) { - n++; - tree = tree->cdr; - } - return n; -} - -#define sym(x) ((mrb_sym)(intptr_t)(x)) -#define lv_name(lv) sym((lv)->car) -static int -lv_idx(codegen_scope *s, mrb_sym id) -{ - node *lv = s->lv; - int n = 1; - - while (lv) { - if (lv_name(lv) == id) return n; - n++; - lv = lv->cdr; - } - return 0; -} - -static void -for_body(codegen_scope *s, node *tree) -{ - codegen_scope *prev = s; - int idx; - struct loopinfo *lp; - node *n2; - mrb_code c; - - /* generate receiver */ - codegen(s, tree->cdr->car, VAL); - /* generate loop-block */ - s = scope_new(s->mrb, s, NULL); - if (s == NULL) { - raise_error(prev, "unexpected scope"); - } - - push(); /* push for a block parameter */ - - lp = loop_push(s, LOOP_FOR); - lp->pc1 = new_label(s); - - /* generate loop variable */ - n2 = tree->car; - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); - if (n2->car && !n2->car->cdr && !n2->cdr) { - gen_assignment(s, n2->car->car, 1, NOVAL); - } - else { - gen_vmassignment(s, n2, 1, VAL); - } - codegen(s, tree->cdr->cdr->car, VAL); - pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - loop_pop(s, NOVAL); - scope_finish(s); - s = prev; - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); - pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); -} - -static int -lambda_body(codegen_scope *s, node *tree, int blk) -{ - mrb_code c; - codegen_scope *parent = s; - s = scope_new(s->mrb, s, tree->car); - if (s == NULL) { - raise_error(parent, "unexpected scope"); - } - - s->mscope = !blk; - - if (blk) { - struct loopinfo *lp = loop_push(s, LOOP_BLOCK); - lp->pc1 = new_label(s); - } - tree = tree->cdr; - if (tree->car) { - mrb_aspec a; - int ma, oa, ra, pa, ka, kd, ba; - int pos, i; - node *n, *opt; - - ma = node_len(tree->car->car); - n = tree->car->car; - while (n) { - n = n->cdr; - } - oa = node_len(tree->car->cdr->car); - ra = tree->car->cdr->cdr->car ? 1 : 0; - pa = node_len(tree->car->cdr->cdr->cdr->car); - ka = kd = 0; - ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; - - a = ((mrb_aspec)(ma & 0x1f) << 18) - | ((mrb_aspec)(oa & 0x1f) << 13) - | ((ra & 1) << 12) - | ((pa & 0x1f) << 7) - | ((ka & 0x1f) << 2) - | ((kd & 1)<< 1) - | (ba & 1); - s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ - | ((ra & 1) << 5) - | (pa & 0x1f); - genop(s, MKOP_Ax(OP_ENTER, a)); - pos = new_label(s); - for (i=0; i 0) { - genop(s, MKOP_sBx(OP_JMP, 0)); - } - opt = tree->car->cdr->car; - i = 0; - while (opt) { - int idx; - - dispatch(s, pos+i); - codegen(s, opt->car->cdr, VAL); - idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car); - pop(); - genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); - i++; - opt = opt->cdr; - } - if (oa > 0) { - dispatch(s, pos+i); - } - } - codegen(s, tree->cdr->car, VAL); - pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { - if (s->nregs == 0) { - genop(s, MKOP_A(OP_LOADNIL, 0)); - genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - } - } - if (blk) { - loop_pop(s, NOVAL); - } - scope_finish(s); - return parent->irep->rlen - 1; -} - -static int -scope_body(codegen_scope *s, node *tree, int val) -{ - codegen_scope *scope = scope_new(s->mrb, s, tree->car); - if (scope == NULL) { - raise_error(s, "unexpected scope"); - } - - codegen(scope, tree->cdr, VAL); - if (!s->iseq) { - genop(scope, MKOP_A(OP_STOP, 0)); - } - else if (!val) { - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - if (scope->nregs == 0) { - genop(scope, MKOP_A(OP_LOADNIL, 0)); - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); - } - } - scope_finish(scope); - if (!s->irep) { - /* should not happen */ - return 0; - } - return s->irep->rlen - 1; -} - -static mrb_bool -nosplat(node *t) -{ - while (t) { - if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE; - t = t->cdr; - } - return TRUE; -} - -static mrb_sym -attrsym(codegen_scope *s, mrb_sym a) -{ - const char *name; - mrb_int len; - char *name2; - - name = mrb_sym2name_len(s->mrb, a, &len); - name2 = (char *)codegen_palloc(s, - (size_t)len - + 1 /* '=' */ - + 1 /* '\0' */ - ); - mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); - memcpy(name2, name, (size_t)len); - name2[len] = '='; - name2[len+1] = '\0'; - - return mrb_intern(s->mrb, name2, len+1); -} - -static int -gen_values(codegen_scope *s, node *t, int val) -{ - int n = 0; - int is_splat; - - while (t) { - is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */ - if (n >= 127 || is_splat) { - if (val) { - pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); - push(); - codegen(s, t->car, VAL); - pop(); pop(); - if (is_splat) { - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); - } - else { - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - } - t = t->cdr; - while (t) { - push(); - codegen(s, t->car, VAL); - pop(); pop(); - if ((intptr_t)t->car->car == NODE_SPLAT) { - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); - } - else { - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - } - t = t->cdr; - } - } - else { - codegen(s, t->car->cdr, NOVAL); - t = t->cdr; - while (t) { - codegen(s, t->car, NOVAL); - t = t->cdr; - } - } - return -1; - } - /* normal (no splat) mode */ - codegen(s, t->car, val); - n++; - t = t->cdr; - } - return n; -} - -#define CALL_MAXARGS 127 - -static void -gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val) -{ - mrb_sym sym = name ? name : sym(tree->cdr->car); - int idx; - int n = 0, noop = 0, sendv = 0, blk = 0; - - codegen(s, tree->car, VAL); /* receiver */ - idx = new_msym(s, sym); - tree = tree->cdr->cdr->car; - if (tree) { - n = gen_values(s, tree->car, VAL); - if (n < 0) { - n = noop = sendv = 1; - push(); - } - } - if (sp) { - if (sendv) { - pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); - push(); - } - else { - genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); - push(); - n++; - } - } - if (tree && tree->cdr) { - noop = 1; - codegen(s, tree->cdr, VAL); - pop(); - } - else { - blk = cursp(); - } - push();pop(); - pop_n(n+1); - { - mrb_int symlen; - const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); - - if (!noop && symlen == 1 && symname[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); - } - else if (!noop && symlen == 1 && symname[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); - } - else if (!noop && symlen == 1 && symname[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); - } - else if (!noop && symlen == 1 && symname[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); - } - else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=') { - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); - } - else { - if (sendv) n = CALL_MAXARGS; - if (blk > 0) { /* no block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); - } - else { - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); - } - } - } - if (val) { - push(); - } -} - -static void -gen_assignment(codegen_scope *s, node *tree, int sp, int val) -{ - int idx; - int type = (intptr_t)tree->car; - - tree = tree->cdr; - switch ((intptr_t)type) { - case NODE_GVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); - break; - case NODE_LVAR: - idx = lv_idx(s, sym(tree)); - if (idx > 0) { - if (idx != sp) { - genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); - } - break; - } - else { /* upvar */ - int lv = 0; - codegen_scope *up = s->prev; - - while (up) { - idx = lv_idx(up, sym(tree)); - if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); - break; - } - lv++; - up = up->prev; - } - } - break; - case NODE_IVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); - break; - case NODE_CVAR: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); - break; - case NODE_CONST: - idx = new_sym(s, sym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); - break; - case NODE_COLON2: - idx = new_sym(s, sym(tree->cdr)); - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); - push(); - codegen(s, tree->car, VAL); - pop_n(2); - genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); - break; - - case NODE_CALL: - push(); - gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL); - pop(); - if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); - } - break; - - case NODE_MASGN: - gen_vmassignment(s, tree->car, sp, val); - break; - - /* splat without assignment */ - case NODE_NIL: - break; - - default: -#ifdef ENABLE_STDIO - printf("unknown lhs %d\n", type); -#endif - break; - } - if (val) push(); -} - -static void -gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) -{ - int n = 0, post = 0; - node *t, *p; - - if (tree->car) { /* pre */ - t = tree->car; - n = 0; - while (t) { - genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n)); - gen_assignment(s, t->car, cursp(), NOVAL); - n++; - t = t->cdr; - } - } - t = tree->cdr; - if (t) { - if (t->cdr) { /* post count */ - p = t->cdr->car; - while (p) { - post++; - p = p->cdr; - } - } - if (val) { - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); - } - else { - pop(); - } - genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); - n = 1; - if (t->car) { /* rest */ - gen_assignment(s, t->car, cursp(), NOVAL); - } - if (t->cdr && t->cdr->car) { - t = t->cdr->car; - while (t) { - gen_assignment(s, t->car, cursp()+n, NOVAL); - t = t->cdr; - n++; - } - } - push(); - } -} - -static void -gen_send_intern(codegen_scope *s) -{ - pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); - push(); -} -static void -gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) -{ - if (val) { - int i = 0, j = 0; - - while (tree) { - switch ((intptr_t)tree->car->car) { - case NODE_STR: - if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0)) - break; - /* fall through */ - case NODE_BEGIN: - codegen(s, tree->car, VAL); - ++j; - break; - - case NODE_LITERAL_DELIM: - if (j > 0) { - j = 0; - ++i; - if (sym) - gen_send_intern(s); - } - break; - } - if (j >= 2) { - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - j = 1; - } - tree = tree->cdr; - } - if (j > 0) { - ++i; - if (sym) - gen_send_intern(s); - } - pop_n(i); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); - push(); - } - else { - while (tree) { - switch ((intptr_t)tree->car->car) { - case NODE_BEGIN: case NODE_BLOCK: - codegen(s, tree->car, NOVAL); - } - tree = tree->cdr; - } - } -} - -static void -raise_error(codegen_scope *s, const char *msg) -{ - int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); - - genop(s, MKOP_ABx(OP_ERR, 1, idx)); -} - -static double -readint_float(codegen_scope *s, const char *p, int base) -{ - const char *e = p + strlen(p); - double f = 0; - int n; - - if (*p == '+') p++; - while (p < e) { - char c = *p; - c = tolower((unsigned char)c); - for (n=0; n= 2 && base <= 36); - if (*p == '+') p++; - while (p < e) { - char c = *p; - c = tolower((unsigned char)c); - for (n=0; n result) { - *overflow = TRUE; - return 0; - } - result *= base; - result -= n; - } - else { - if ((MRB_INT_MAX - n)/base < result) { - *overflow = TRUE; - return 0; - } - result *= base; - result += n; - } - p++; - } - *overflow = FALSE; - return result; -} - -static void -codegen(codegen_scope *s, node *tree, int val) -{ - int nt; - - if (!tree) return; - - if (s->irep && s->filename_index != tree->filename_index) { - s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); - s->debug_start_pos = s->pc; - s->filename_index = tree->filename_index; - s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); - } - - nt = (intptr_t)tree->car; - s->lineno = tree->lineno; - tree = tree->cdr; - switch (nt) { - case NODE_BEGIN: - if (val && !tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - while (tree) { - codegen(s, tree->car, tree->cdr ? NOVAL : val); - tree = tree->cdr; - } - break; - - case NODE_RESCUE: - { - int onerr, noexc, exend, pos1, pos2, tmp; - struct loopinfo *lp; - - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); - lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; - if (tree->car) { - codegen(s, tree->car, val); - if (val) pop(); - } - lp->type = LOOP_RESCUE; - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); - dispatch(s, onerr); - tree = tree->cdr; - exend = 0; - pos1 = 0; - if (tree->car) { - node *n2 = tree->car; - int exc = cursp(); - - genop(s, MKOP_A(OP_RESCUE, exc)); - push(); - while (n2) { - node *n3 = n2->car; - node *n4 = n3->car; - - if (pos1) dispatch(s, pos1); - pos2 = 0; - do { - if (n4) { - codegen(s, n4->car, VAL); - } - else { - genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); - push(); - } - genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); - pop(); - if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); - } - else { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); - } - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); - pos2 = tmp; - if (n4) { - n4 = n4->cdr; - } - } while (n4); - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch_linked(s, pos2); - - pop(); - if (n3->cdr->car) { - gen_assignment(s, n3->cdr->car, exc, NOVAL); - } - if (n3->cdr->cdr->car) { - codegen(s, n3->cdr->cdr->car, val); - if (val) pop(); - } - tmp = genop(s, MKOP_sBx(OP_JMP, exend)); - exend = tmp; - n2 = n2->cdr; - push(); - } - if (pos1) { - dispatch(s, pos1); - genop(s, MKOP_A(OP_RAISE, exc)); - } - } - pop(); - tree = tree->cdr; - dispatch(s, noexc); - genop(s, MKOP_A(OP_POPERR, 1)); - if (tree->car) { - codegen(s, tree->car, val); - } - else if (val) { - push(); - } - dispatch_linked(s, exend); - loop_pop(s, NOVAL); - } - break; - - case NODE_ENSURE: - { - int idx; - int epush = s->pc; - - genop(s, MKOP_Bx(OP_EPUSH, 0)); - s->ensure_level++; - codegen(s, tree->car, val); - idx = scope_body(s, tree->cdr, NOVAL); - s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); - s->ensure_level--; - genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); - } - break; - - case NODE_LAMBDA: - { - int idx = lambda_body(s, tree, 1); - - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); - push(); - } - break; - - case NODE_BLOCK: - { - int idx = lambda_body(s, tree, 1); - - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); - push(); - } - break; - - case NODE_IF: - { - int pos1, pos2; - node *e = tree->cdr->cdr->car; - - codegen(s, tree->car, VAL); - pop(); - pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); - - codegen(s, tree->cdr->car, val); - if (val && !(tree->cdr->car)) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - if (e) { - if (val) pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch(s, pos1); - codegen(s, e, val); - dispatch(s, pos2); - } - else { - if (val) { - pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch(s, pos1); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - dispatch(s, pos2); - push(); - } - else { - dispatch(s, pos1); - } - } - } - break; - - case NODE_AND: - { - int pos; - - codegen(s, tree->car, VAL); - pop(); - pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } - break; - - case NODE_OR: - { - int pos; - - codegen(s, tree->car, VAL); - pop(); - pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); - codegen(s, tree->cdr, val); - dispatch(s, pos); - } - break; - - case NODE_WHILE: - { - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); - - loop_pop(s, val); - } - break; - - case NODE_UNTIL: - { - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); - - loop_pop(s, val); - } - break; - - case NODE_FOR: - for_body(s, tree); - if (val) push(); - break; - - case NODE_CASE: - { - int head = 0; - int pos1, pos2, pos3, tmp; - node *n; - - pos3 = 0; - if (tree->car) { - head = cursp(); - codegen(s, tree->car, VAL); - } - tree = tree->cdr; - while (tree) { - n = tree->car->car; - pos1 = pos2 = 0; - while (n) { - codegen(s, n->car, VAL); - if (head) { - genop(s, MKOP_AB(OP_MOVE, cursp(), head)); - pop(); - if ((intptr_t)n->car->car == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); - } - else { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); - } - } - else { - pop(); - } - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); - pos2 = tmp; - n = n->cdr; - } - if (tree->car->car) { - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); - dispatch_linked(s, pos2); - } - codegen(s, tree->car->cdr, val); - if (val) pop(); - tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); - pos3 = tmp; - if (pos1) dispatch(s, pos1); - tree = tree->cdr; - } - if (val) { - int pos = cursp(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - if (pos3) dispatch_linked(s, pos3); - if (head) pop(); - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); - push(); - } - else { - if (pos3) { - dispatch_linked(s, pos3); - } - if (head) { - pop(); - } - } - } - break; - - case NODE_SCOPE: - scope_body(s, tree, NOVAL); - break; - - case NODE_FCALL: - case NODE_CALL: - gen_call(s, tree, 0, 0, val); - break; - - case NODE_DOT2: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); - push(); - } - break; - - case NODE_DOT3: - codegen(s, tree->car, val); - codegen(s, tree->cdr, val); - if (val) { - pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); - push(); - } - break; - - case NODE_COLON2: - { - int sym = new_sym(s, sym(tree->cdr)); - - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - if (val) push(); - } - break; - - case NODE_COLON3: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - if (val) push(); - } - break; - - case NODE_ARRAY: - { - int n; - - n = gen_values(s, tree, val); - if (n >= 0) { - if (val) { - pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); - push(); - } - } - else if (val) { - push(); - } - } - break; - - case NODE_HASH: - { - int len = 0; - mrb_bool update = FALSE; - - while (tree) { - codegen(s, tree->car->car, val); - codegen(s, tree->car->cdr, val); - len++; - tree = tree->cdr; - if (val && len == 126) { - pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { - pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); - } - push(); - update = TRUE; - len = 0; - } - } - if (val) { - pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { - pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); - } - push(); - } - } - break; - - case NODE_SPLAT: - codegen(s, tree, VAL); - break; - - case NODE_ASGN: - codegen(s, tree->cdr, VAL); - pop(); - gen_assignment(s, tree->car, cursp(), val); - break; - - case NODE_MASGN: - { - int len = 0, n = 0, post = 0; - node *t = tree->cdr, *p; - int rhs = cursp(); - - if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) { - /* fixed rhs */ - t = t->cdr; - while (t) { - codegen(s, t->car, VAL); - len++; - t = t->cdr; - } - tree = tree->car; - if (tree->car) { /* pre */ - t = tree->car; - n = 0; - while (t) { - gen_assignment(s, t->car, rhs+n, NOVAL); - n++; - t = t->cdr; - } - } - t = tree->cdr; - if (t) { - if (t->cdr) { /* post count */ - p = t->cdr->car; - while (p) { - post++; - p = p->cdr; - } - } - if (t->car) { /* rest (len - pre - post) */ - int rn; - - if (len < post + n) { - rn = 0; - } - else { - rn = len - post - n; - } - genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); - gen_assignment(s, t->car, cursp(), NOVAL); - n += rn; - } - if (t->cdr && t->cdr->car) { - t = t->cdr->car; - while (ncar, rhs+n, NOVAL); - t = t->cdr; - n++; - } - } - } - pop_n(len); - if (val) { - genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); - push(); - } - } - else { - /* variable rhs */ - codegen(s, t, VAL); - gen_vmassignment(s, tree->car, rhs, val); - if (!val) { - pop(); - } - } - } - break; - - case NODE_OP_ASGN: - { - mrb_sym sym = sym(tree->cdr->car); - mrb_int len; - const char *name = mrb_sym2name_len(s->mrb, sym, &len); - int idx; - - codegen(s, tree->car, VAL); - if (len == 2 && - ((name[0] == '|' && name[1] == '|') || - (name[0] == '&' && name[1] == '&'))) { - int pos; - - pop(); - pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL); - codegen(s, tree->cdr->cdr->car, VAL); - pop(); - gen_assignment(s, tree->car, cursp(), val); - dispatch(s, pos); - break; - } - codegen(s, tree->cdr->cdr->car, VAL); - push(); pop(); - pop(); pop(); - - idx = new_msym(s, sym); - if (len == 1 && name[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); - } - else if (len == 1 && name[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); - } - else if (len == 1 && name[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); - } - else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); - } - else if (len == 1 && name[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); - } - else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); - } - else { - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); - } - } - gen_assignment(s, tree->car, cursp(), val); - break; - - case NODE_SUPER: - { - int n = 0, noop = 0, sendv = 0; - - push(); /* room for receiver */ - if (tree) { - node *args = tree->car; - if (args) { - n = gen_values(s, args, VAL); - if (n < 0) { - n = noop = sendv = 1; - push(); - } - } - } - if (tree && tree->cdr) { - codegen(s, tree->cdr, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); pop(); - } - pop_n(n+1); - if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); - if (val) push(); - } - break; - - case NODE_ZSUPER: - { - codegen_scope *s2 = s; - int lv = 0, ainfo = 0; - - push(); /* room for receiver */ - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); - push(); push(); pop(); /* ARGARY pushes two values */ - if (tree && tree->cdr) { - codegen(s, tree->cdr, VAL); - pop(); - } - pop(); pop(); - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); - if (val) push(); - } - break; - - case NODE_RETURN: - if (tree) { - codegen(s, tree, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - if (s->loop) { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - if (val) push(); - break; - - case NODE_YIELD: - { - codegen_scope *s2 = s; - int lv = 0, ainfo = 0; - int n = 0, sendv = 0; - - while (!s2->mscope) { - lv++; - s2 = s2->prev; - if (!s2) break; - } - if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); - push(); - if (tree) { - n = gen_values(s, tree, VAL); - if (n < 0) { - n = sendv = 1; - push(); - } - } - pop_n(n+1); - if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); - if (val) push(); - } - break; - - case NODE_BREAK: - loop_break(s, tree); - if (val) push(); - break; - - case NODE_NEXT: - if (!s->loop) { - raise_error(s, "unexpected next"); - } - else if (s->loop->type == LOOP_NORMAL) { - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - codegen(s, tree, NOVAL); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); - } - else { - if (tree) { - codegen(s, tree, VAL); - pop(); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - if (val) push(); - break; - - case NODE_REDO: - if (!s->loop) { - raise_error(s, "unexpected redo"); - } - else { - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); - } - break; - - case NODE_RETRY: - { - const char *msg = "unexpected retry"; - - if (!s->loop) { - raise_error(s, msg); - } - else { - struct loopinfo *lp = s->loop; - int n = 0; - - while (lp && lp->type != LOOP_RESCUE) { - if (lp->type == LOOP_BEGIN) { - n++; - } - lp = lp->prev; - } - if (!lp) { - raise_error(s, msg); - } - else { - if (n > 0) { - while (n--) { - genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); - } - } - if (s->ensure_level > lp->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); - } - genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); - } - } - } - break; - - case NODE_LVAR: - if (val) { - int idx = lv_idx(s, sym(tree)); - - if (idx > 0) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); - } - else { - int lv = 0; - codegen_scope *up = s->prev; - - while (up) { - idx = lv_idx(up, sym(tree)); - if (idx > 0) { - genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv)); - break; - } - lv++; - up = up->prev; - } - } - push(); - } - break; - - case NODE_GVAR: - if (val) { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); - } - break; - - case NODE_IVAR: - if (val) { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); - push(); - } - break; - - case NODE_CVAR: - if (val) { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); - push(); - } - break; - - case NODE_CONST: - { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - push(); - } - break; - - case NODE_DEFINED: - codegen(s, tree, VAL); - break; - - case NODE_BACK_REF: - if (val) { - char buf[2] = { '$' }; - mrb_value str; - int sym; - - buf[1] = (char)(intptr_t)tree; - str = mrb_str_new(s->mrb, buf, 2); - sym = new_sym(s, mrb_intern_str(s->mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); - } - break; - - case NODE_NTH_REF: - if (val) { - int sym; - mrb_state *mrb = s->mrb; - mrb_value fix = mrb_fixnum_value((intptr_t)tree); - mrb_value str = mrb_str_buf_new(mrb, 4); - - mrb_str_cat_lit(mrb, str, "$"); - mrb_str_cat_str(mrb, str, mrb_fixnum_to_str(mrb, fix, 10)); - sym = new_sym(s, mrb_intern_str(mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); - } - break; - - case NODE_ARG: - /* should not happen */ - break; - - case NODE_BLOCK_ARG: - codegen(s, tree, VAL); - break; - - case NODE_INT: - if (val) { - char *p = (char*)tree->car; - int base = (intptr_t)tree->cdr->car; - mrb_int i; - mrb_code co; - mrb_bool overflow; - - i = readint_mrb_int(s, p, base, FALSE, &overflow); - if (overflow) { - double f = readint_float(s, p, base); - int off = new_lit(s, mrb_float_value(s->mrb, f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - } - else { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } - else { - int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); - } - genop(s, co); - } - push(); - } - break; - - case NODE_FLOAT: - if (val) { - char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); - int off = new_lit(s, mrb_float_value(s->mrb, f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - push(); - } - break; - - case NODE_NEGATE: - { - nt = (intptr_t)tree->car; - tree = tree->cdr; - switch (nt) { - case NODE_FLOAT: - { - char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); - int off = new_lit(s, mrb_float_value(s->mrb, -f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - push(); - } - break; - - case NODE_INT: - { - char *p = (char*)tree->car; - int base = (intptr_t)tree->cdr->car; - mrb_int i; - mrb_code co; - mrb_bool overflow; - - i = readint_mrb_int(s, p, base, TRUE, &overflow); - if (overflow) { - double f = readint_float(s, p, base); - int off = new_lit(s, mrb_float_value(s->mrb, -f)); - - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); - } - else { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } - else { - int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); - } - genop(s, co); - } - push(); - } - break; - - default: - { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); - - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); - push(); - codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); - } - break; - } - } - break; - - case NODE_STR: - if (val) { - char *p = (char*)tree->car; - size_t len = (intptr_t)tree->cdr; - int ai = mrb_gc_arena_save(s->mrb); - int off = new_lit(s, mrb_str_new(s->mrb, p, len)); - - mrb_gc_arena_restore(s->mrb, ai); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - push(); - } - break; - - case NODE_HEREDOC: - tree = ((struct mrb_parser_heredoc_info *)tree)->doc; - /* fall through */ - case NODE_DSTR: - if (val) { - node *n = tree; - - if (!n) break; - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - n = n->cdr; - } - } - else { - node *n = tree; - - while (n) { - if ((intptr_t)n->car->car != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } - break; - - case NODE_WORDS: - gen_literal_array(s, tree, FALSE, val); - break; - - case NODE_SYMBOLS: - gen_literal_array(s, tree, TRUE, val); - break; - - case NODE_DXSTR: - { - node *n; - int ai = mrb_gc_arena_save(s->mrb); - int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); - - if (val == NOVAL) { push(); } - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - codegen(s, tree->car, VAL); - n = tree->cdr; - while (n) { - if ((intptr_t)n->car->car == NODE_XSTR) { - n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; - mrb_assert(!n->cdr); /* must be the end */ - } - codegen(s, n->car, VAL); - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - n = n->cdr; - } - pop(); - pop(); - sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); - if (val == NOVAL) { pop(); } - else { push(); } - mrb_gc_arena_restore(s->mrb, ai); - } - break; - - case NODE_XSTR: - { - char *p = (char*)tree->car; - size_t len = (intptr_t)tree->cdr; - int ai = mrb_gc_arena_save(s->mrb); - int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); - int off = new_lit(s, mrb_str_new(s->mrb, p, len)); - - if (val == NOVAL) { push(); } - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - pop(); - sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); - if (val == NOVAL) { pop(); } - else { push(); } - mrb_gc_arena_restore(s->mrb, ai); - } - break; - - case NODE_REGX: - if (val) { - char *p1 = (char*)tree->car; - char *p2 = (char*)tree->cdr; - int ai = mrb_gc_arena_save(s->mrb); - int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); - int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); - int argc = 1; - - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - if (p2) { - push(); - off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - argc++; - pop(); - } - pop(); - sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); - mrb_gc_arena_restore(s->mrb, ai); - push(); - } - break; - - case NODE_DREGX: - if (val) { - node *n = tree->car; - int ai = mrb_gc_arena_save(s->mrb); - int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); - int argc = 1; - int off; - char *p; - - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); - push(); - codegen(s, n->car, VAL); - n = n->cdr; - while (n) { - codegen(s, n->car, VAL); - pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - push(); - n = n->cdr; - } - n = tree->cdr->cdr; - if (n->car) { - p = (char*)n->car; - off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); - codegen(s, tree->car, VAL); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); - } - if (n->cdr) { - char *p2 = (char*)n->cdr; - - push(); - off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); - argc++; - pop(); - } - pop(); - sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); - mrb_gc_arena_restore(s->mrb, ai); - push(); - } - else { - node *n = tree->car; - - while (n) { - if ((intptr_t)n->car->car != NODE_STR) { - codegen(s, n->car, NOVAL); - } - n = n->cdr; - } - } - break; - - case NODE_SYM: - if (val) { - int sym = new_sym(s, sym(tree)); - - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - break; - - case NODE_DSYM: - codegen(s, tree, val); - if (val) { - gen_send_intern(s); - } - break; - - case NODE_SELF: - if (val) { - genop(s, MKOP_A(OP_LOADSELF, cursp())); - push(); - } - break; - - case NODE_NIL: - if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - break; - - case NODE_TRUE: - if (val) { - genop(s, MKOP_A(OP_LOADT, cursp())); - push(); - } - break; - - case NODE_FALSE: - if (val) { - genop(s, MKOP_A(OP_LOADF, cursp())); - push(); - } - break; - - case NODE_ALIAS: - { - int a = new_msym(s, sym(tree->car)); - int b = new_msym(s, sym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); - push(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - pop_n(3); - genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); - if (val) { - push(); - } - } - break; - - case NODE_UNDEF: - { - int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); - int num = 0; - node *t = tree; - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - while (t) { - int symbol = new_msym(s, sym(t->car)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - push(); - t = t->cdr; - num++; - } - pop_n(num + 1); - genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); - if (val) { - push(); - } - } - break; - - case NODE_CLASS: - { - int idx; - - if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); - push(); - } - else { - codegen(s, tree->car->car, VAL); - } - if (tree->cdr->car) { - codegen(s, tree->cdr->car, VAL); - } - else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - pop(); pop(); - idx = new_msym(s, sym(tree->car->cdr)); - genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); - idx = scope_body(s, tree->cdr->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_MODULE: - { - int idx; - - if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - } - else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); - push(); - } - else { - codegen(s, tree->car->car, VAL); - } - pop(); - idx = new_msym(s, sym(tree->car->cdr)); - genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_SCLASS: - { - int idx; - - codegen(s, tree->car, VAL); - pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); - if (val) { - push(); - } - } - break; - - case NODE_DEF: - { - int sym = new_msym(s, sym(tree->car)); - int idx = lambda_body(s, tree->cdr, 0); - - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); - push(); pop(); - pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); - if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - } - break; - - case NODE_SDEF: - { - node *recv = tree->car; - int sym = new_msym(s, sym(tree->cdr->car)); - int idx = lambda_body(s, tree->cdr->cdr, 0); - - codegen(s, recv, VAL); - pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); - pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); - if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); - push(); - } - } - break; - - case NODE_POSTEXE: - codegen(s, tree, NOVAL); - break; - - default: - break; - } -} - -static void -scope_add_irep(codegen_scope *s, mrb_irep *irep) -{ - if (s->irep == NULL) { - s->irep = irep; - return; - } - if (s->irep->rlen == s->rcapa) { - s->rcapa *= 2; - s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa); - } - s->irep->reps[s->irep->rlen] = irep; - s->irep->rlen++; -} - -static codegen_scope* -scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) -{ - static const codegen_scope codegen_scope_zero = { 0 }; - mrb_pool *pool = mrb_pool_open(mrb); - codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); - - if (!p) return NULL; - *p = codegen_scope_zero; - p->mrb = mrb; - p->mpool = pool; - if (!prev) return p; - p->prev = prev; - p->ainfo = -1; - p->mscope = 0; - - p->irep = mrb_add_irep(mrb); - scope_add_irep(prev, p->irep); - - p->rcapa = 8; - p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa); - - p->icapa = 1024; - p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa); - p->irep->iseq = p->iseq; - - p->pcapa = 32; - p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); - p->irep->plen = 0; - - p->scapa = 256; - p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); - p->irep->slen = 0; - - p->lv = lv; - p->sp += node_len(lv)+1; /* add self */ - p->nlocals = p->sp; - if (lv) { - node *n = lv; - size_t i = 0; - - p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1)); - for (i=0, n=lv; n; i++,n=n->cdr) { - p->irep->lv[i].name = lv_name(n); - if (lv_name(n)) { - p->irep->lv[i].r = lv_idx(p, lv_name(n)); - } - else { - p->irep->lv[i].r = 0; - } - } - mrb_assert(i + 1 == p->nlocals); - } - p->ai = mrb_gc_arena_save(mrb); - - p->filename = prev->filename; - if (p->filename) { - p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa); - } - p->lineno = prev->lineno; - - /* debug setting */ - p->debug_start_pos = 0; - if (p->filename) { - mrb_debug_info_alloc(mrb, p->irep); - p->irep->filename = p->filename; - p->irep->lines = p->lines; - } - else { - p->irep->debug_info = NULL; - } - p->parser = prev->parser; - p->filename_index = prev->filename_index; - - return p; -} - -static void -scope_finish(codegen_scope *s) -{ - mrb_state *mrb = s->mrb; - mrb_irep *irep = s->irep; - size_t fname_len; - char *fname; - - irep->flags = 0; - if (s->iseq) { - irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); - irep->ilen = s->pc; - if (s->lines) { - irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); - } - else { - irep->lines = 0; - } - } - irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); - irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); - irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); - if (s->filename) { - s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc); - - fname_len = strlen(s->filename); - fname = (char*)codegen_malloc(s, fname_len + 1); - memcpy(fname, s->filename, fname_len); - fname[fname_len] = '\0'; - irep->filename = fname; - } - - irep->nlocals = s->nlocals; - irep->nregs = s->nregs; - - mrb_gc_arena_restore(mrb, s->ai); - mrb_pool_close(s->mpool); -} - -static struct loopinfo* -loop_push(codegen_scope *s, enum looptype t) -{ - struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); - - p->type = t; - p->pc1 = p->pc2 = p->pc3 = 0; - p->prev = s->loop; - p->ensure_level = s->ensure_level; - p->acc = cursp(); - s->loop = p; - - return p; -} - -static void -loop_break(codegen_scope *s, node *tree) -{ - if (!s->loop) { - codegen(s, tree, NOVAL); - raise_error(s, "unexpected break"); - } - else { - struct loopinfo *loop; - - if (tree) { - codegen(s, tree, VAL); - pop(); - } - - loop = s->loop; - while (loop->type == LOOP_BEGIN) { - genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); - loop = loop->prev; - } - while (loop->type == LOOP_RESCUE) { - loop = loop->prev; - } - if (loop->type == LOOP_NORMAL) { - int tmp; - - if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); - } - if (tree) { - genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); - } - tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); - loop->pc3 = tmp; - } - else { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); - } - } -} - -static void -loop_pop(codegen_scope *s, int val) -{ - if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); - } - dispatch_linked(s, s->loop->pc3); - s->loop = s->loop->prev; - if (val) push(); -} - -MRB_API struct RProc* -mrb_generate_code(mrb_state *mrb, parser_state *p) -{ - codegen_scope *scope = scope_new(mrb, 0, 0); - struct RProc *proc; - - if (!scope) { - return NULL; - } - scope->mrb = mrb; - scope->parser = p; - scope->filename = p->filename; - scope->filename_index = p->current_filename_index; - - MRB_TRY(&scope->jmp) { - /* prepare irep */ - codegen(scope, p->tree, NOVAL); - proc = mrb_proc_new(mrb, scope->irep); - mrb_irep_decref(mrb, scope->irep); - mrb_pool_close(scope->mpool); - return proc; - } - MRB_CATCH(&scope->jmp) { - if (scope->filename == scope->irep->filename) { - scope->irep->filename = NULL; - } - mrb_irep_decref(mrb, scope->irep); - mrb_pool_close(scope->mpool); - return NULL; - } - MRB_END_EXC(&scope->jmp); -} diff --git a/src/keywords b/src/keywords deleted file mode 100644 index 9cb86608c..000000000 --- a/src/keywords +++ /dev/null @@ -1,50 +0,0 @@ -%{ -struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) -%} - -struct kwtable; -%% -__ENCODING__, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END -__FILE__, {keyword__FILE__, keyword__FILE__}, EXPR_END -__LINE__, {keyword__LINE__, keyword__LINE__}, EXPR_END -BEGIN, {keyword_BEGIN, keyword_BEGIN}, EXPR_END -END, {keyword_END, keyword_END}, EXPR_END -alias, {keyword_alias, keyword_alias}, EXPR_FNAME -and, {keyword_and, keyword_and}, EXPR_VALUE -begin, {keyword_begin, keyword_begin}, EXPR_BEG -break, {keyword_break, keyword_break}, EXPR_MID -case, {keyword_case, keyword_case}, EXPR_VALUE -class, {keyword_class, keyword_class}, EXPR_CLASS -def, {keyword_def, keyword_def}, EXPR_FNAME -do, {keyword_do, keyword_do}, EXPR_BEG -else, {keyword_else, keyword_else}, EXPR_BEG -elsif, {keyword_elsif, keyword_elsif}, EXPR_VALUE -end, {keyword_end, keyword_end}, EXPR_END -ensure, {keyword_ensure, keyword_ensure}, EXPR_BEG -false, {keyword_false, keyword_false}, EXPR_END -for, {keyword_for, keyword_for}, EXPR_VALUE -if, {keyword_if, modifier_if}, EXPR_VALUE -in, {keyword_in, keyword_in}, EXPR_VALUE -module, {keyword_module, keyword_module}, EXPR_VALUE -next, {keyword_next, keyword_next}, EXPR_MID -nil, {keyword_nil, keyword_nil}, EXPR_END -not, {keyword_not, keyword_not}, EXPR_ARG -or, {keyword_or, keyword_or}, EXPR_VALUE -redo, {keyword_redo, keyword_redo}, EXPR_END -rescue, {keyword_rescue, modifier_rescue}, EXPR_MID -retry, {keyword_retry, keyword_retry}, EXPR_END -return, {keyword_return, keyword_return}, EXPR_MID -self, {keyword_self, keyword_self}, EXPR_END -super, {keyword_super, keyword_super}, EXPR_ARG -then, {keyword_then, keyword_then}, EXPR_BEG -true, {keyword_true, keyword_true}, EXPR_END -undef, {keyword_undef, keyword_undef}, EXPR_FNAME -unless, {keyword_unless, modifier_unless}, EXPR_VALUE -until, {keyword_until, modifier_until}, EXPR_VALUE -when, {keyword_when, keyword_when}, EXPR_VALUE -while, {keyword_while, modifier_while}, EXPR_VALUE -yield, {keyword_yield, keyword_yield}, EXPR_ARG -%% diff --git a/src/lex.def b/src/lex.def deleted file mode 100644 index ea456a843..000000000 --- a/src/lex.def +++ /dev/null @@ -1,212 +0,0 @@ -/* ANSI-C code produced by gperf version 3.0.3 */ -/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - -#line 1 "src/keywords" - -struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) -#line 8 "src/keywords" -struct kwtable; - -#define TOTAL_KEYWORDS 40 -#define MIN_WORD_LENGTH 2 -#define MAX_WORD_LENGTH 12 -#define MIN_HASH_VALUE 8 -#define MAX_HASH_VALUE 50 -/* maximum key range = 43, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (register const char *str, register unsigned int len) -{ - static const unsigned char asso_values[] = - { - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 14, 51, 16, 8, - 11, 13, 51, 51, 51, 51, 10, 51, 13, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 11, 51, 13, 1, 26, - 4, 1, 8, 28, 51, 23, 51, 1, 1, 27, - 5, 19, 21, 51, 8, 3, 3, 11, 51, 21, - 24, 16, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51 - }; - register int hval = len; - - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[2]]; - /*FALLTHROUGH*/ - case 2: - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval + asso_values[(unsigned char)str[len - 1]]; -} - -#ifdef __GNUC__ -__inline -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const struct kwtable * -mrb_reserved_word (register const char *str, register unsigned int len) -{ - static const struct kwtable wordlist[] = - { - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 18 "src/keywords" - {"break", {keyword_break, keyword_break}, EXPR_MID}, -#line 23 "src/keywords" - {"else", {keyword_else, keyword_else}, EXPR_BEG}, -#line 33 "src/keywords" - {"nil", {keyword_nil, keyword_nil}, EXPR_END}, -#line 26 "src/keywords" - {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, -#line 25 "src/keywords" - {"end", {keyword_end, keyword_end}, EXPR_END}, -#line 42 "src/keywords" - {"then", {keyword_then, keyword_then}, EXPR_BEG}, -#line 34 "src/keywords" - {"not", {keyword_not, keyword_not}, EXPR_ARG}, -#line 27 "src/keywords" - {"false", {keyword_false, keyword_false}, EXPR_END}, -#line 40 "src/keywords" - {"self", {keyword_self, keyword_self}, EXPR_END}, -#line 24 "src/keywords" - {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, -#line 37 "src/keywords" - {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, -#line 43 "src/keywords" - {"true", {keyword_true, keyword_true}, EXPR_END}, -#line 46 "src/keywords" - {"until", {keyword_until, modifier_until}, EXPR_VALUE}, -#line 45 "src/keywords" - {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, -#line 39 "src/keywords" - {"return", {keyword_return, keyword_return}, EXPR_MID}, -#line 21 "src/keywords" - {"def", {keyword_def, keyword_def}, EXPR_FNAME}, -#line 16 "src/keywords" - {"and", {keyword_and, keyword_and}, EXPR_VALUE}, -#line 22 "src/keywords" - {"do", {keyword_do, keyword_do}, EXPR_BEG}, -#line 49 "src/keywords" - {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, -#line 28 "src/keywords" - {"for", {keyword_for, keyword_for}, EXPR_VALUE}, -#line 44 "src/keywords" - {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, -#line 35 "src/keywords" - {"or", {keyword_or, keyword_or}, EXPR_VALUE}, -#line 30 "src/keywords" - {"in", {keyword_in, keyword_in}, EXPR_VALUE}, -#line 47 "src/keywords" - {"when", {keyword_when, keyword_when}, EXPR_VALUE}, -#line 38 "src/keywords" - {"retry", {keyword_retry, keyword_retry}, EXPR_END}, -#line 29 "src/keywords" - {"if", {keyword_if, modifier_if}, EXPR_VALUE}, -#line 19 "src/keywords" - {"case", {keyword_case, keyword_case}, EXPR_VALUE}, -#line 36 "src/keywords" - {"redo", {keyword_redo, keyword_redo}, EXPR_END}, -#line 32 "src/keywords" - {"next", {keyword_next, keyword_next}, EXPR_MID}, -#line 41 "src/keywords" - {"super", {keyword_super, keyword_super}, EXPR_ARG}, -#line 31 "src/keywords" - {"module", {keyword_module, keyword_module}, EXPR_VALUE}, -#line 17 "src/keywords" - {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, -#line 12 "src/keywords" - {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, -#line 11 "src/keywords" - {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, -#line 10 "src/keywords" - {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, -#line 14 "src/keywords" - {"END", {keyword_END, keyword_END}, EXPR_END}, -#line 15 "src/keywords" - {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, -#line 13 "src/keywords" - {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, - {""}, -#line 20 "src/keywords" - {"class", {keyword_class, keyword_class}, EXPR_CLASS}, - {""}, {""}, -#line 48 "src/keywords" - {"while", {keyword_while, modifier_while}, EXPR_VALUE} - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register const char *s = wordlist[key].name; - - if (*str == *s && !strcmp (str + 1, s + 1)) - return &wordlist[key]; - } - } - return 0; -} -#line 50 "src/keywords" - diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 88fca83fc..abde441d5 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -3,76 +3,17 @@ MRuby.each_target do relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" - lex_def = "#{current_dir}/lex.def" objs = Dir.glob("#{current_dir}/*.c").map { |f| - next nil if cxx_abi_enabled? and f =~ /(codegen|error|vm).c$/ + next nil if cxx_abi_enabled? and f =~ /(error|vm).c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact if cxx_abi_enabled? - cxx_abi_dependency = %w(codegen error vm) - cxx_abi_objs = cxx_abi_dependency.map { |v| - src = "#{current_build_dir}/#{v}.cxx" - file src => ["#{current_dir}/#{v}.c", __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write < src do |t| - cxx.run t.name, t.prerequisites.first, [], [current_dir] - end - - objfile src - } - cxx_abi_objs << objfile("#{current_build_dir}/y.tab") - - file "#{current_build_dir}/y.tab.cxx" => ["#{current_build_dir}/y.tab.c", __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write < ["#{current_build_dir}/y.tab.cxx", lex_def] do |t| - cxx.run t.name, t.prerequisites.first, [], [current_dir] - end - - objs += cxx_abi_objs - else - objs += [objfile("#{current_build_dir}/y.tab")] - file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.c", lex_def] do |t| - cc.run t.name, t.prerequisites.first, [], [current_dir] - end + objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end self.libmruby << objs file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| archiver.run t.name, t.prerequisites end - - # Parser - file "#{current_build_dir}/y.tab.c" => ["#{current_dir}/parse.y"] do |t| - yacc.run t.name, t.prerequisites.first - end - - # Lexical analyzer - file lex_def => "#{current_dir}/keywords" do |t| - gperf.run t.name, t.prerequisites.first - end end diff --git a/src/node.h b/src/node.h deleted file mode 100644 index 532a8323a..000000000 --- a/src/node.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -** node.h - nodes of abstract syntax tree -** -** See Copyright Notice in mruby.h -*/ - -#ifndef NODE_H -#define NODE_H - -enum node_type { - NODE_METHOD, - NODE_FBODY, - NODE_CFUNC, - NODE_SCOPE, - NODE_BLOCK, - NODE_IF, - NODE_CASE, - NODE_WHEN, - NODE_OPT_N, - NODE_WHILE, - NODE_UNTIL, - NODE_ITER, - NODE_FOR, - NODE_BREAK, - NODE_NEXT, - NODE_REDO, - NODE_RETRY, - NODE_BEGIN, - NODE_RESCUE, - NODE_ENSURE, - NODE_AND, - NODE_OR, - NODE_NOT, - NODE_MASGN, - NODE_ASGN, - NODE_CDECL, - NODE_CVASGN, - NODE_CVDECL, - NODE_OP_ASGN, - NODE_CALL, - NODE_FCALL, - NODE_VCALL, - NODE_SUPER, - NODE_ZSUPER, - NODE_ARRAY, - NODE_ZARRAY, - NODE_HASH, - NODE_RETURN, - NODE_YIELD, - NODE_LVAR, - NODE_DVAR, - NODE_GVAR, - NODE_IVAR, - NODE_CONST, - NODE_CVAR, - NODE_NTH_REF, - NODE_BACK_REF, - NODE_MATCH, - NODE_MATCH2, - NODE_MATCH3, - NODE_INT, - NODE_FLOAT, - NODE_NEGATE, - NODE_LAMBDA, - NODE_SYM, - NODE_STR, - NODE_DSTR, - NODE_XSTR, - NODE_DXSTR, - NODE_REGX, - NODE_DREGX, - NODE_DREGX_ONCE, - NODE_LIST, - NODE_ARG, - NODE_ARGSCAT, - NODE_ARGSPUSH, - NODE_SPLAT, - NODE_TO_ARY, - NODE_SVALUE, - NODE_BLOCK_ARG, - NODE_DEF, - NODE_SDEF, - NODE_ALIAS, - NODE_UNDEF, - NODE_CLASS, - NODE_MODULE, - NODE_SCLASS, - NODE_COLON2, - NODE_COLON3, - NODE_CREF, - NODE_DOT2, - NODE_DOT3, - NODE_FLIP2, - NODE_FLIP3, - NODE_ATTRSET, - NODE_SELF, - NODE_NIL, - NODE_TRUE, - NODE_FALSE, - NODE_DEFINED, - NODE_NEWLINE, - NODE_POSTEXE, - NODE_ALLOCA, - NODE_DMETHOD, - NODE_BMETHOD, - NODE_MEMO, - NODE_IFUNC, - NODE_DSYM, - NODE_ATTRASGN, - NODE_HEREDOC, - NODE_LITERAL_DELIM, - NODE_WORDS, - NODE_SYMBOLS, - NODE_LAST -}; - -#endif /* NODE_H */ diff --git a/src/parse.y b/src/parse.y deleted file mode 100644 index 5b17649a9..000000000 --- a/src/parse.y +++ /dev/null @@ -1,6420 +0,0 @@ -/* -** parse.y - mruby parser -** -** See Copyright Notice in mruby.h -*/ - -%{ -#undef PARSER_DEBUG -#ifdef PARSER_DEBUG -# define YYDEBUG 1 -#endif -#define YYERROR_VERBOSE 1 -/* - * Force yacc to use our memory management. This is a little evil because - * the macros assume that "parser_state *p" is in scope - */ -#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) -#define YYFREE(o) mrb_free(p->mrb, (o)) -#define YYSTACK_USE_ALLOCA 0 - -#include -#include -#include -#include -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/proc.h" -#include "mruby/error.h" -#include "node.h" -#include "mruby/throw.h" - -#define YYLEX_PARAM p - -typedef mrb_ast_node node; -typedef struct mrb_parser_state parser_state; -typedef struct mrb_parser_heredoc_info parser_heredoc_info; - -static int yyparse(parser_state *p); -static int yylex(void *lval, parser_state *p); -static void yyerror(parser_state *p, const char *s); -static void yywarn(parser_state *p, const char *s); -static void yywarning(parser_state *p, const char *s); -static void backref_error(parser_state *p, node *n); -static void tokadd(parser_state *p, int32_t c); - -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - -typedef unsigned int stack_type; - -#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1)) -#define BITSTACK_POP(stack) ((stack) = (stack) >> 1) -#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1)) -#define BITSTACK_SET_P(stack) ((stack)&1) - -#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n)) -#define COND_POP() BITSTACK_POP(p->cond_stack) -#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack) -#define COND_P() BITSTACK_SET_P(p->cond_stack) - -#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n)) -#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack) -#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack) -#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) - -#define SET_LINENO(c,n) ((c)->lineno = (n)) -#define NODE_LINENO(c,n) do {\ - if (n) {\ - (c)->filename_index = (n)->filename_index;\ - (c)->lineno = (n)->lineno;\ - }\ -} while (0) - -#define sym(x) ((mrb_sym)(intptr_t)(x)) -#define nsym(x) ((node*)(intptr_t)(x)) - -static inline mrb_sym -intern_cstr_gen(parser_state *p, const char *s) -{ - return mrb_intern_cstr(p->mrb, s); -} -#define intern_cstr(s) intern_cstr_gen(p,(s)) - -static inline mrb_sym -intern_gen(parser_state *p, const char *s, size_t len) -{ - return mrb_intern(p->mrb, s, len); -} -#define intern(s,len) intern_gen(p,(s),(len)) - -static inline mrb_sym -intern_gen_c(parser_state *p, const char c) -{ - return mrb_intern(p->mrb, &c, 1); -} -#define intern_c(c) intern_gen_c(p,(c)) - -static void -cons_free_gen(parser_state *p, node *cons) -{ - cons->cdr = p->cells; - p->cells = cons; -} -#define cons_free(c) cons_free_gen(p, (c)) - -static void* -parser_palloc(parser_state *p, size_t size) -{ - void *m = mrb_pool_alloc(p->pool, size); - - if (!m) { - MRB_THROW(p->jmp); - } - return m; -} - -static node* -cons_gen(parser_state *p, node *car, node *cdr) -{ - node *c; - - if (p->cells) { - c = p->cells; - p->cells = p->cells->cdr; - } - else { - c = (node *)parser_palloc(p, sizeof(mrb_ast_node)); - } - - c->car = car; - c->cdr = cdr; - c->lineno = p->lineno; - c->filename_index = p->current_filename_index; - return c; -} -#define cons(a,b) cons_gen(p,(a),(b)) - -static node* -list1_gen(parser_state *p, node *a) -{ - return cons(a, 0); -} -#define list1(a) list1_gen(p, (a)) - -static node* -list2_gen(parser_state *p, node *a, node *b) -{ - return cons(a, cons(b,0)); -} -#define list2(a,b) list2_gen(p, (a),(b)) - -static node* -list3_gen(parser_state *p, node *a, node *b, node *c) -{ - return cons(a, cons(b, cons(c,0))); -} -#define list3(a,b,c) list3_gen(p, (a),(b),(c)) - -static node* -list4_gen(parser_state *p, node *a, node *b, node *c, node *d) -{ - return cons(a, cons(b, cons(c, cons(d, 0)))); -} -#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d)) - -static node* -list5_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e) -{ - return cons(a, cons(b, cons(c, cons(d, cons(e, 0))))); -} -#define list5(a,b,c,d,e) list5_gen(p, (a),(b),(c),(d),(e)) - -static node* -list6_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e, node *f) -{ - return cons(a, cons(b, cons(c, cons(d, cons(e, cons(f, 0)))))); -} -#define list6(a,b,c,d,e,f) list6_gen(p, (a),(b),(c),(d),(e),(f)) - -static node* -append_gen(parser_state *p, node *a, node *b) -{ - node *c = a; - - if (!a) return b; - while (c->cdr) { - c = c->cdr; - } - if (b) { - c->cdr = b; - } - return a; -} -#define append(a,b) append_gen(p,(a),(b)) -#define push(a,b) append_gen(p,(a),list1(b)) - -static char* -parser_strndup(parser_state *p, const char *s, size_t len) -{ - char *b = (char *)parser_palloc(p, len+1); - - memcpy(b, s, len); - b[len] = '\0'; - return b; -} -#undef strndup -#define strndup(s,len) parser_strndup(p, s, len) - -static char* -parser_strdup(parser_state *p, const char *s) -{ - return parser_strndup(p, s, strlen(s)); -} -#undef strdup -#define strdup(s) parser_strdup(p, s) - -/* xxx ----------------------------- */ - -static node* -local_switch(parser_state *p) -{ - node *prev = p->locals; - - p->locals = cons(0, 0); - return prev; -} - -static void -local_resume(parser_state *p, node *prev) -{ - p->locals = prev; -} - -static void -local_nest(parser_state *p) -{ - p->locals = cons(0, p->locals); -} - -static void -local_unnest(parser_state *p) -{ - if (p->locals) { - p->locals = p->locals->cdr; - } -} - -static mrb_bool -local_var_p(parser_state *p, mrb_sym sym) -{ - node *l = p->locals; - - while (l) { - node *n = l->car; - while (n) { - if (sym(n->car) == sym) return TRUE; - n = n->cdr; - } - l = l->cdr; - } - return FALSE; -} - -static void -local_add_f(parser_state *p, mrb_sym sym) -{ - if (p->locals) { - p->locals->car = push(p->locals->car, nsym(sym)); - } -} - -static void -local_add(parser_state *p, mrb_sym sym) -{ - if (!local_var_p(p, sym)) { - local_add_f(p, sym); - } -} - -static node* -locals_node(parser_state *p) -{ - return p->locals ? p->locals->car : NULL; -} - -/* (:scope (vars..) (prog...)) */ -static node* -new_scope(parser_state *p, node *body) -{ - return cons((node*)NODE_SCOPE, cons(locals_node(p), body)); -} - -/* (:begin prog...) */ -static node* -new_begin(parser_state *p, node *body) -{ - if (body) { - return list2((node*)NODE_BEGIN, body); - } - return cons((node*)NODE_BEGIN, 0); -} - -#define newline_node(n) (n) - -/* (:rescue body rescue else) */ -static node* -new_rescue(parser_state *p, node *body, node *resq, node *els) -{ - return list4((node*)NODE_RESCUE, body, resq, els); -} - -/* (:ensure body ensure) */ -static node* -new_ensure(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_ENSURE, cons(a, cons(0, b))); -} - -/* (:nil) */ -static node* -new_nil(parser_state *p) -{ - return list1((node*)NODE_NIL); -} - -/* (:true) */ -static node* -new_true(parser_state *p) -{ - return list1((node*)NODE_TRUE); -} - -/* (:false) */ -static node* -new_false(parser_state *p) -{ - return list1((node*)NODE_FALSE); -} - -/* (:alias new old) */ -static node* -new_alias(parser_state *p, mrb_sym a, mrb_sym b) -{ - return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b))); -} - -/* (:if cond then else) */ -static node* -new_if(parser_state *p, node *a, node *b, node *c) -{ - return list4((node*)NODE_IF, a, b, c); -} - -/* (:unless cond then else) */ -static node* -new_unless(parser_state *p, node *a, node *b, node *c) -{ - return list4((node*)NODE_IF, a, c, b); -} - -/* (:while cond body) */ -static node* -new_while(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_WHILE, cons(a, b)); -} - -/* (:until cond body) */ -static node* -new_until(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_UNTIL, cons(a, b)); -} - -/* (:for var obj body) */ -static node* -new_for(parser_state *p, node *v, node *o, node *b) -{ - return list4((node*)NODE_FOR, v, o, b); -} - -/* (:case a ((when ...) body) ((when...) body)) */ -static node* -new_case(parser_state *p, node *a, node *b) -{ - node *n = list2((node*)NODE_CASE, a); - node *n2 = n; - - while (n2->cdr) { - n2 = n2->cdr; - } - n2->cdr = b; - return n; -} - -/* (:postexe a) */ -static node* -new_postexe(parser_state *p, node *a) -{ - return cons((node*)NODE_POSTEXE, a); -} - -/* (:self) */ -static node* -new_self(parser_state *p) -{ - return list1((node*)NODE_SELF); -} - -/* (:call a b c) */ -static node* -new_call(parser_state *p, node *a, mrb_sym b, node *c) -{ - node *n = list4((node*)NODE_CALL, a, nsym(b), c); - NODE_LINENO(n, a); - return n; -} - -/* (:fcall self mid args) */ -static node* -new_fcall(parser_state *p, mrb_sym b, node *c) -{ - node *n = new_self(p); - NODE_LINENO(n, c); - n = list4((node*)NODE_FCALL, n, nsym(b), c); - NODE_LINENO(n, c); - return n; -} - -/* (:super . c) */ -static node* -new_super(parser_state *p, node *c) -{ - return cons((node*)NODE_SUPER, c); -} - -/* (:zsuper) */ -static node* -new_zsuper(parser_state *p) -{ - return list1((node*)NODE_ZSUPER); -} - -/* (:yield . c) */ -static node* -new_yield(parser_state *p, node *c) -{ - if (c) { - if (c->cdr) { - yyerror(p, "both block arg and actual block given"); - } - return cons((node*)NODE_YIELD, c->car); - } - return cons((node*)NODE_YIELD, 0); -} - -/* (:return . c) */ -static node* -new_return(parser_state *p, node *c) -{ - return cons((node*)NODE_RETURN, c); -} - -/* (:break . c) */ -static node* -new_break(parser_state *p, node *c) -{ - return cons((node*)NODE_BREAK, c); -} - -/* (:next . c) */ -static node* -new_next(parser_state *p, node *c) -{ - return cons((node*)NODE_NEXT, c); -} - -/* (:redo) */ -static node* -new_redo(parser_state *p) -{ - return list1((node*)NODE_REDO); -} - -/* (:retry) */ -static node* -new_retry(parser_state *p) -{ - return list1((node*)NODE_RETRY); -} - -/* (:dot2 a b) */ -static node* -new_dot2(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_DOT2, cons(a, b)); -} - -/* (:dot3 a b) */ -static node* -new_dot3(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_DOT3, cons(a, b)); -} - -/* (:colon2 b c) */ -static node* -new_colon2(parser_state *p, node *b, mrb_sym c) -{ - return cons((node*)NODE_COLON2, cons(b, nsym(c))); -} - -/* (:colon3 . c) */ -static node* -new_colon3(parser_state *p, mrb_sym c) -{ - return cons((node*)NODE_COLON3, nsym(c)); -} - -/* (:and a b) */ -static node* -new_and(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_AND, cons(a, b)); -} - -/* (:or a b) */ -static node* -new_or(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_OR, cons(a, b)); -} - -/* (:array a...) */ -static node* -new_array(parser_state *p, node *a) -{ - return cons((node*)NODE_ARRAY, a); -} - -/* (:splat . a) */ -static node* -new_splat(parser_state *p, node *a) -{ - return cons((node*)NODE_SPLAT, a); -} - -/* (:hash (k . v) (k . v)...) */ -static node* -new_hash(parser_state *p, node *a) -{ - return cons((node*)NODE_HASH, a); -} - -/* (:sym . a) */ -static node* -new_sym(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_SYM, nsym(sym)); -} - -static mrb_sym -new_strsym(parser_state *p, node* str) -{ - const char *s = (const char*)str->cdr->car; - size_t len = (size_t)str->cdr->cdr; - - return mrb_intern(p->mrb, s, len); -} - -/* (:lvar . a) */ -static node* -new_lvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_LVAR, nsym(sym)); -} - -/* (:gvar . a) */ -static node* -new_gvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_GVAR, nsym(sym)); -} - -/* (:ivar . a) */ -static node* -new_ivar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_IVAR, nsym(sym)); -} - -/* (:cvar . a) */ -static node* -new_cvar(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_CVAR, nsym(sym)); -} - -/* (:const . a) */ -static node* -new_const(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_CONST, nsym(sym)); -} - -/* (:undef a...) */ -static node* -new_undef(parser_state *p, mrb_sym sym) -{ - return list2((node*)NODE_UNDEF, nsym(sym)); -} - -/* (:class class super body) */ -static node* -new_class(parser_state *p, node *c, node *s, node *b) -{ - return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b)); -} - -/* (:sclass obj body) */ -static node* -new_sclass(parser_state *p, node *o, node *b) -{ - return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b)); -} - -/* (:module module body) */ -static node* -new_module(parser_state *p, node *m, node *b) -{ - return list3((node*)NODE_MODULE, m, cons(locals_node(p), b)); -} - -/* (:def m lv (arg . body)) */ -static node* -new_def(parser_state *p, mrb_sym m, node *a, node *b) -{ - return list5((node*)NODE_DEF, nsym(m), locals_node(p), a, b); -} - -/* (:sdef obj m lv (arg . body)) */ -static node* -new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b) -{ - return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b); -} - -/* (:arg . sym) */ -static node* -new_arg(parser_state *p, mrb_sym sym) -{ - return cons((node*)NODE_ARG, nsym(sym)); -} - -/* (m o r m2 b) */ -/* m: (a b c) */ -/* o: ((a . e1) (b . e2)) */ -/* r: a */ -/* m2: (a b c) */ -/* b: a */ -static node* -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) -{ - node *n; - - n = cons(m2, nsym(blk)); - n = cons(nsym(rest), n); - n = cons(opt, n); - return cons(m, n); -} - -/* (:block_arg . a) */ -static node* -new_block_arg(parser_state *p, node *a) -{ - return cons((node*)NODE_BLOCK_ARG, a); -} - -/* (:block arg body) */ -static node* -new_block(parser_state *p, node *a, node *b) -{ - return list4((node*)NODE_BLOCK, locals_node(p), a, b); -} - -/* (:lambda arg body) */ -static node* -new_lambda(parser_state *p, node *a, node *b) -{ - return list4((node*)NODE_LAMBDA, locals_node(p), a, b); -} - -/* (:asgn lhs rhs) */ -static node* -new_asgn(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_ASGN, cons(a, b)); -} - -/* (:masgn mlhs=(pre rest post) mrhs) */ -static node* -new_masgn(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_MASGN, cons(a, b)); -} - -/* (:asgn lhs rhs) */ -static node* -new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) -{ - return list4((node*)NODE_OP_ASGN, a, nsym(op), b); -} - -/* (:int . i) */ -static node* -new_int(parser_state *p, const char *s, int base) -{ - return list3((node*)NODE_INT, (node*)strdup(s), (node*)(intptr_t)base); -} - -/* (:float . i) */ -static node* -new_float(parser_state *p, const char *s) -{ - return cons((node*)NODE_FLOAT, (node*)strdup(s)); -} - -/* (:str . (s . len)) */ -static node* -new_str(parser_state *p, const char *s, int len) -{ - return cons((node*)NODE_STR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); -} - -/* (:dstr . a) */ -static node* -new_dstr(parser_state *p, node *a) -{ - return cons((node*)NODE_DSTR, a); -} - -/* (:str . (s . len)) */ -static node* -new_xstr(parser_state *p, const char *s, int len) -{ - return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); -} - -/* (:xstr . a) */ -static node* -new_dxstr(parser_state *p, node *a) -{ - return cons((node*)NODE_DXSTR, a); -} - -/* (:dsym . a) */ -static node* -new_dsym(parser_state *p, node *a) -{ - return cons((node*)NODE_DSYM, new_dstr(p, a)); -} - -/* (:str . (a . a)) */ -static node* -new_regx(parser_state *p, const char *p1, const char* p2) -{ - return cons((node*)NODE_REGX, cons((node*)p1, (node*)p2)); -} - -/* (:dregx . a) */ -static node* -new_dregx(parser_state *p, node *a, node *b) -{ - return cons((node*)NODE_DREGX, cons(a, b)); -} - -/* (:backref . n) */ -static node* -new_back_ref(parser_state *p, int n) -{ - return cons((node*)NODE_BACK_REF, (node*)(intptr_t)n); -} - -/* (:nthref . n) */ -static node* -new_nth_ref(parser_state *p, int n) -{ - return cons((node*)NODE_NTH_REF, (node*)(intptr_t)n); -} - -/* (:heredoc . a) */ -static node* -new_heredoc(parser_state *p) -{ - parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info)); - return cons((node*)NODE_HEREDOC, (node*)inf); -} - -static void -new_bv(parser_state *p, mrb_sym id) -{ -} - -static node* -new_literal_delim(parser_state *p) -{ - return cons((node*)NODE_LITERAL_DELIM, 0); -} - -/* (:words . a) */ -static node* -new_words(parser_state *p, node *a) -{ - return cons((node*)NODE_WORDS, a); -} - -/* (:symbols . a) */ -static node* -new_symbols(parser_state *p, node *a) -{ - return cons((node*)NODE_SYMBOLS, a); -} - -/* xxx ----------------------------- */ - -/* (:call a op) */ -static node* -call_uni_op(parser_state *p, node *recv, const char *m) -{ - return new_call(p, recv, intern_cstr(m), 0); -} - -/* (:call a op b) */ -static node* -call_bin_op(parser_state *p, node *recv, const char *m, node *arg1) -{ - return new_call(p, recv, intern_cstr(m), list1(list1(arg1))); -} - -static void -args_with_block(parser_state *p, node *a, node *b) -{ - if (b) { - if (a->cdr) { - yyerror(p, "both block arg and actual block given"); - } - a->cdr = b; - } -} - -static void -call_with_block(parser_state *p, node *a, node *b) -{ - node *n; - - if (a->car == (node*)NODE_SUPER || - a->car == (node*)NODE_ZSUPER) { - if (!a->cdr) a->cdr = cons(0, b); - else { - args_with_block(p, a->cdr, b); - } - } - else { - n = a->cdr->cdr->cdr; - if (!n->car) n->car = cons(0, b); - else { - args_with_block(p, n->car, b); - } - } -} - -static node* -negate_lit(parser_state *p, node *n) -{ - return cons((node*)NODE_NEGATE, n); -} - -static node* -cond(node *n) -{ - return n; -} - -static node* -ret_args(parser_state *p, node *n) -{ - if (n->cdr) { - yyerror(p, "block argument should not be given"); - return NULL; - } - if (!n->car->cdr) return n->car->car; - return new_array(p, n->car); -} - -static void -assignable(parser_state *p, node *lhs) -{ - if ((int)(intptr_t)lhs->car == NODE_LVAR) { - local_add(p, sym(lhs->cdr)); - } -} - -static node* -var_reference(parser_state *p, node *lhs) -{ - node *n; - - if ((int)(intptr_t)lhs->car == NODE_LVAR) { - if (!local_var_p(p, sym(lhs->cdr))) { - n = new_fcall(p, sym(lhs->cdr), 0); - cons_free(lhs); - return n; - } - } - - return lhs; -} - -typedef enum mrb_string_type string_type; - -static node* -new_strterm(parser_state *p, string_type type, int term, int paren) -{ - return cons((node*)(intptr_t)type, cons((node*)0, cons((node*)(intptr_t)paren, (node*)(intptr_t)term))); -} - -static void -end_strterm(parser_state *p) -{ - cons_free(p->lex_strterm->cdr->cdr); - cons_free(p->lex_strterm->cdr); - cons_free(p->lex_strterm); - p->lex_strterm = NULL; -} - -static parser_heredoc_info * -parsing_heredoc_inf(parser_state *p) -{ - node *nd = p->parsing_heredoc; - if (nd == NULL) - return NULL; - /* mrb_assert(nd->car->car == NODE_HEREDOC); */ - return (parser_heredoc_info*)nd->car->cdr; -} - -static void -heredoc_treat_nextline(parser_state *p) -{ - if (p->heredocs_from_nextline == NULL) - return; - if (p->parsing_heredoc == NULL) { - node *n; - p->parsing_heredoc = p->heredocs_from_nextline; - p->lex_strterm_before_heredoc = p->lex_strterm; - p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0); - n = p->all_heredocs; - if (n) { - while (n->cdr) - n = n->cdr; - n->cdr = p->parsing_heredoc; - } - else { - p->all_heredocs = p->parsing_heredoc; - } - } - else { - node *n, *m; - m = p->heredocs_from_nextline; - while (m->cdr) - m = m->cdr; - n = p->all_heredocs; - mrb_assert(n != NULL); - if (n == p->parsing_heredoc) { - m->cdr = n; - p->all_heredocs = p->heredocs_from_nextline; - p->parsing_heredoc = p->heredocs_from_nextline; - } - else { - while (n->cdr != p->parsing_heredoc) { - n = n->cdr; - mrb_assert(n != NULL); - } - m->cdr = n->cdr; - n->cdr = p->heredocs_from_nextline; - p->parsing_heredoc = p->heredocs_from_nextline; - } - } - p->heredocs_from_nextline = NULL; -} - -static void -heredoc_end(parser_state *p) -{ - p->parsing_heredoc = p->parsing_heredoc->cdr; - if (p->parsing_heredoc == NULL) { - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - end_strterm(p); - p->lex_strterm = p->lex_strterm_before_heredoc; - p->lex_strterm_before_heredoc = NULL; - p->heredoc_end_now = TRUE; - } - else { - /* next heredoc */ - p->lex_strterm->car = (node*)(intptr_t)parsing_heredoc_inf(p)->type; - } -} -#define is_strterm_type(p,str_func) ((int)(intptr_t)((p)->lex_strterm->car) & (str_func)) - -/* xxx ----------------------------- */ - -%} - -%pure-parser -%parse-param {parser_state *p} -%lex-param {parser_state *p} - -%union { - node *nd; - mrb_sym id; - int num; - stack_type stack; - const struct vtable *vars; -} - -%token - keyword_class - keyword_module - keyword_def - keyword_begin - keyword_if - keyword_unless - keyword_while - keyword_until - keyword_for - -%token - keyword_undef - keyword_rescue - keyword_ensure - keyword_end - keyword_then - keyword_elsif - keyword_else - keyword_case - keyword_when - keyword_break - keyword_next - keyword_redo - keyword_retry - keyword_in - keyword_do - keyword_do_cond - keyword_do_block - keyword_do_LAMBDA - keyword_return - keyword_yield - keyword_super - keyword_self - keyword_nil - keyword_true - keyword_false - keyword_and - keyword_or - keyword_not - modifier_if - modifier_unless - modifier_while - modifier_until - modifier_rescue - keyword_alias - keyword_BEGIN - keyword_END - keyword__LINE__ - keyword__FILE__ - keyword__ENCODING__ - -%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL -%token tINTEGER tFLOAT tCHAR tXSTRING tREGEXP -%token tSTRING tSTRING_PART tSTRING_MID -%token tNTH_REF tBACK_REF -%token tREGEXP_END - -%type singleton string string_rep string_interp xstring regexp -%type literal numeric cpath symbol -%type top_compstmt top_stmts top_stmt -%type bodystmt compstmt stmts stmt expr arg primary command command_call method_call -%type expr_value arg_value primary_value -%type if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure -%type args call_args opt_call_args -%type paren_args opt_paren_args variable -%type command_args aref_args opt_block_arg block_arg var_ref var_lhs -%type command_asgn mrhs superclass block_call block_command -%type f_block_optarg f_block_opt -%type f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs -%type assoc_list assocs assoc undef_list backref for_var -%type block_param opt_block_param block_param_def f_opt -%type bv_decls opt_bv_decl bvar f_larglist lambda_body -%type brace_block cmd_brace_block do_block lhs none f_bad_arg -%type mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner -%type fsym sym basic_symbol operation operation2 operation3 -%type cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn -%type heredoc words symbols - -%token tUPLUS /* unary+ */ -%token tUMINUS /* unary- */ -%token tPOW /* ** */ -%token tCMP /* <=> */ -%token tEQ /* == */ -%token tEQQ /* === */ -%token tNEQ /* != */ -%token tGEQ /* >= */ -%token tLEQ /* <= */ -%token tANDOP tOROP /* && and || */ -%token tMATCH tNMATCH /* =~ and !~ */ -%token tDOT2 tDOT3 /* .. and ... */ -%token tAREF tASET /* [] and []= */ -%token tLSHFT tRSHFT /* << and >> */ -%token tCOLON2 /* :: */ -%token tCOLON3 /* :: at EXPR_BEG */ -%token tOP_ASGN /* +=, -= etc. */ -%token tASSOC /* => */ -%token tLPAREN /* ( */ -%token tLPAREN_ARG /* ( */ -%token tRPAREN /* ) */ -%token tLBRACK /* [ */ -%token tLBRACE /* { */ -%token tLBRACE_ARG /* { */ -%token tSTAR /* * */ -%token tAMPER /* & */ -%token tLAMBDA /* -> */ -%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG -%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG -%token tHEREDOC_BEG /* <<, <<- */ -%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM -%token tHD_STRING_PART tHD_STRING_MID - -/* - * precedence table - */ - -%nonassoc tLOWEST -%nonassoc tLBRACE_ARG - -%nonassoc modifier_if modifier_unless modifier_while modifier_until -%left keyword_or keyword_and -%right keyword_not -%right '=' tOP_ASGN -%left modifier_rescue -%right '?' ':' -%nonassoc tDOT2 tDOT3 -%left tOROP -%left tANDOP -%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH -%left '>' tGEQ '<' tLEQ -%left '|' '^' -%left '&' -%left tLSHFT tRSHFT -%left '+' '-' -%left '*' '/' '%' -%right tUMINUS_NUM tUMINUS -%right tPOW -%right '!' '~' tUPLUS - -%token tLAST_TOKEN - -%% -program : { - p->lstate = EXPR_BEG; - if (!p->locals) p->locals = cons(0,0); - } - top_compstmt - { - p->tree = new_scope(p, $2); - NODE_LINENO(p->tree, $2); - } - ; - -top_compstmt : top_stmts opt_terms - { - $$ = $1; - } - ; - -top_stmts : none - { - $$ = new_begin(p, 0); - } - | top_stmt - { - $$ = new_begin(p, $1); - NODE_LINENO($$, $1); - } - | top_stmts terms top_stmt - { - $$ = push($1, newline_node($3)); - } - | error top_stmt - { - $$ = new_begin(p, 0); - } - ; - -top_stmt : stmt - | keyword_BEGIN - { - $$ = local_switch(p); - } - '{' top_compstmt '}' - { - yyerror(p, "BEGIN not supported"); - local_resume(p, $2); - $$ = 0; - } - ; - -bodystmt : compstmt - opt_rescue - opt_else - opt_ensure - { - if ($2) { - $$ = new_rescue(p, $1, $2, $3); - NODE_LINENO($$, $1); - } - else if ($3) { - yywarn(p, "else without rescue is useless"); - $$ = push($1, $3); - } - else { - $$ = $1; - } - if ($4) { - if ($$) { - $$ = new_ensure(p, $$, $4); - } - else { - $$ = push($4, new_nil(p)); - } - } - } - ; - -compstmt : stmts opt_terms - { - $$ = $1; - } - ; - -stmts : none - { - $$ = new_begin(p, 0); - } - | stmt - { - $$ = new_begin(p, $1); - NODE_LINENO($$, $1); - } - | stmts terms stmt - { - $$ = push($1, newline_node($3)); - } - | error stmt - { - $$ = new_begin(p, $2); - } - ; - -stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym - { - $$ = new_alias(p, $2, $4); - } - | keyword_undef undef_list - { - $$ = $2; - } - | stmt modifier_if expr_value - { - $$ = new_if(p, cond($3), $1, 0); - } - | stmt modifier_unless expr_value - { - $$ = new_unless(p, cond($3), $1, 0); - } - | stmt modifier_while expr_value - { - $$ = new_while(p, cond($3), $1); - } - | stmt modifier_until expr_value - { - $$ = new_until(p, cond($3), $1); - } - | stmt modifier_rescue stmt - { - $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); - } - | keyword_END '{' compstmt '}' - { - yyerror(p, "END not suported"); - $$ = new_postexe(p, $3); - } - | command_asgn - | mlhs '=' command_call - { - $$ = new_masgn(p, $1, $3); - } - | var_lhs tOP_ASGN command_call - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call - { - yyerror(p, "constant re-assignment"); - $$ = 0; - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | backref tOP_ASGN command_call - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | lhs '=' mrhs - { - $$ = new_asgn(p, $1, new_array(p, $3)); - } - | mlhs '=' arg_value - { - $$ = new_masgn(p, $1, $3); - } - | mlhs '=' mrhs - { - $$ = new_masgn(p, $1, new_array(p, $3)); - } - | expr - ; - -command_asgn : lhs '=' command_call - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' command_asgn - { - $$ = new_asgn(p, $1, $3); - } - ; - - -expr : command_call - | expr keyword_and expr - { - $$ = new_and(p, $1, $3); - } - | expr keyword_or expr - { - $$ = new_or(p, $1, $3); - } - | keyword_not opt_nl expr - { - $$ = call_uni_op(p, cond($3), "!"); - } - | '!' command_call - { - $$ = call_uni_op(p, cond($2), "!"); - } - | arg - ; - -expr_value : expr - { - if (!$1) $$ = new_nil(p); - else $$ = $1; - } - ; - -command_call : command - | block_command - ; - -block_command : block_call - | block_call dot_or_colon operation2 command_args - ; - -cmd_brace_block : tLBRACE_ARG - { - local_nest(p); - } - opt_block_param - compstmt - '}' - { - $$ = new_block(p, $3, $4); - local_unnest(p); - } - ; - -command : operation command_args %prec tLOWEST - { - $$ = new_fcall(p, $1, $2); - } - | operation command_args cmd_brace_block - { - args_with_block(p, $2, $3); - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value '.' operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | keyword_super command_args - { - $$ = new_super(p, $2); - } - | keyword_yield command_args - { - $$ = new_yield(p, $2); - } - | keyword_return call_args - { - $$ = new_return(p, ret_args(p, $2)); - } - | keyword_break call_args - { - $$ = new_break(p, ret_args(p, $2)); - } - | keyword_next call_args - { - $$ = new_next(p, ret_args(p, $2)); - } - ; - -mlhs : mlhs_basic - { - $$ = $1; - } - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -mlhs_inner : mlhs_basic - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -mlhs_basic : mlhs_list - { - $$ = list1($1); - } - | mlhs_list mlhs_item - { - $$ = list1(push($1,$2)); - } - | mlhs_list tSTAR mlhs_node - { - $$ = list2($1, $3); - } - | mlhs_list tSTAR mlhs_node ',' mlhs_post - { - $$ = list3($1, $3, $5); - } - | mlhs_list tSTAR - { - $$ = list2($1, new_nil(p)); - } - | mlhs_list tSTAR ',' mlhs_post - { - $$ = list3($1, new_nil(p), $4); - } - | tSTAR mlhs_node - { - $$ = list2(0, $2); - } - | tSTAR mlhs_node ',' mlhs_post - { - $$ = list3(0, $2, $4); - } - | tSTAR - { - $$ = list2(0, new_nil(p)); - } - | tSTAR ',' mlhs_post - { - $$ = list3(0, new_nil(p), $3); - } - ; - -mlhs_item : mlhs_node - | tLPAREN mlhs_inner rparen - { - $$ = new_masgn(p, $2, NULL); - } - ; - -mlhs_list : mlhs_item ',' - { - $$ = list1($1); - } - | mlhs_list mlhs_item ',' - { - $$ = push($1, $2); - } - ; - -mlhs_post : mlhs_item - { - $$ = list1($1); - } - | mlhs_list mlhs_item - { - $$ = push($1, $2); - } - ; - -mlhs_node : variable - { - assignable(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -lhs : variable - { - assignable(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -cname : tIDENTIFIER - { - yyerror(p, "class/module name must be CONSTANT"); - } - | tCONSTANT - ; - -cpath : tCOLON3 cname - { - $$ = cons((node*)1, nsym($2)); - } - | cname - { - $$ = cons((node*)0, nsym($1)); - } - | primary_value tCOLON2 cname - { - $$ = cons($1, nsym($3)); - } - ; - -fname : tIDENTIFIER - | tCONSTANT - | tFID - | op - { - p->lstate = EXPR_ENDFN; - $$ = $1; - } - | reswords - { - p->lstate = EXPR_ENDFN; - $$ = $1; - } - ; - -fsym : fname - | basic_symbol - ; - -undef_list : fsym - { - $$ = new_undef(p, $1); - } - | undef_list ',' {p->lstate = EXPR_FNAME;} fsym - { - $$ = push($1, nsym($4)); - } - ; - -op : '|' { $$ = intern_c('|'); } - | '^' { $$ = intern_c('^'); } - | '&' { $$ = intern_c('&'); } - | tCMP { $$ = intern("<=>",3); } - | tEQ { $$ = intern("==",2); } - | tEQQ { $$ = intern("===",3); } - | tMATCH { $$ = intern("=~",2); } - | tNMATCH { $$ = intern("!~",2); } - | '>' { $$ = intern_c('>'); } - | tGEQ { $$ = intern(">=",2); } - | '<' { $$ = intern_c('<'); } - | tLEQ { $$ = intern("<=",2); } - | tNEQ { $$ = intern("!=",2); } - | tLSHFT { $$ = intern("<<",2); } - | tRSHFT { $$ = intern(">>",2); } - | '+' { $$ = intern_c('+'); } - | '-' { $$ = intern_c('-'); } - | '*' { $$ = intern_c('*'); } - | tSTAR { $$ = intern_c('*'); } - | '/' { $$ = intern_c('/'); } - | '%' { $$ = intern_c('%'); } - | tPOW { $$ = intern("**",2); } - | '!' { $$ = intern_c('!'); } - | '~' { $$ = intern_c('~'); } - | tUPLUS { $$ = intern("+@",2); } - | tUMINUS { $$ = intern("-@",2); } - | tAREF { $$ = intern("[]",2); } - | tASET { $$ = intern("[]=",3); } - | '`' { $$ = intern_c('`'); } - ; - -reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ - | keyword_BEGIN | keyword_END - | keyword_alias | keyword_and | keyword_begin - | keyword_break | keyword_case | keyword_class | keyword_def - | keyword_do | keyword_else | keyword_elsif - | keyword_end | keyword_ensure | keyword_false - | keyword_for | keyword_in | keyword_module | keyword_next - | keyword_nil | keyword_not | keyword_or | keyword_redo - | keyword_rescue | keyword_retry | keyword_return | keyword_self - | keyword_super | keyword_then | keyword_true | keyword_undef - | keyword_when | keyword_yield | keyword_if | keyword_unless - | keyword_while | keyword_until - ; - -arg : lhs '=' arg - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' arg modifier_rescue arg - { - $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | var_lhs tOP_ASGN arg - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | var_lhs tOP_ASGN arg modifier_rescue arg - { - $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | tCOLON3 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | backref tOP_ASGN arg - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | arg tDOT2 arg - { - $$ = new_dot2(p, $1, $3); - } - | arg tDOT3 arg - { - $$ = new_dot3(p, $1, $3); - } - | arg '+' arg - { - $$ = call_bin_op(p, $1, "+", $3); - } - | arg '-' arg - { - $$ = call_bin_op(p, $1, "-", $3); - } - | arg '*' arg - { - $$ = call_bin_op(p, $1, "*", $3); - } - | arg '/' arg - { - $$ = call_bin_op(p, $1, "/", $3); - } - | arg '%' arg - { - $$ = call_bin_op(p, $1, "%", $3); - } - | arg tPOW arg - { - $$ = call_bin_op(p, $1, "**", $3); - } - | tUMINUS_NUM tINTEGER tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUMINUS_NUM tFLOAT tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUPLUS arg - { - $$ = call_uni_op(p, $2, "+@"); - } - | tUMINUS arg - { - $$ = call_uni_op(p, $2, "-@"); - } - | arg '|' arg - { - $$ = call_bin_op(p, $1, "|", $3); - } - | arg '^' arg - { - $$ = call_bin_op(p, $1, "^", $3); - } - | arg '&' arg - { - $$ = call_bin_op(p, $1, "&", $3); - } - | arg tCMP arg - { - $$ = call_bin_op(p, $1, "<=>", $3); - } - | arg '>' arg - { - $$ = call_bin_op(p, $1, ">", $3); - } - | arg tGEQ arg - { - $$ = call_bin_op(p, $1, ">=", $3); - } - | arg '<' arg - { - $$ = call_bin_op(p, $1, "<", $3); - } - | arg tLEQ arg - { - $$ = call_bin_op(p, $1, "<=", $3); - } - | arg tEQ arg - { - $$ = call_bin_op(p, $1, "==", $3); - } - | arg tEQQ arg - { - $$ = call_bin_op(p, $1, "===", $3); - } - | arg tNEQ arg - { - $$ = call_bin_op(p, $1, "!=", $3); - } - | arg tMATCH arg - { - $$ = call_bin_op(p, $1, "=~", $3); - } - | arg tNMATCH arg - { - $$ = call_bin_op(p, $1, "!~", $3); - } - | '!' arg - { - $$ = call_uni_op(p, cond($2), "!"); - } - | '~' arg - { - $$ = call_uni_op(p, cond($2), "~"); - } - | arg tLSHFT arg - { - $$ = call_bin_op(p, $1, "<<", $3); - } - | arg tRSHFT arg - { - $$ = call_bin_op(p, $1, ">>", $3); - } - | arg tANDOP arg - { - $$ = new_and(p, $1, $3); - } - | arg tOROP arg - { - $$ = new_or(p, $1, $3); - } - | arg '?' arg opt_nl ':' arg - { - $$ = new_if(p, cond($1), $3, $6); - } - | primary - { - $$ = $1; - } - ; - -arg_value : arg - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -aref_args : none - | args trailer - { - $$ = $1; - NODE_LINENO($$, $1); - } - | args ',' assocs trailer - { - $$ = push($1, new_hash(p, $3)); - } - | assocs trailer - { - $$ = cons(new_hash(p, $1), 0); - NODE_LINENO($$, $1); - } - ; - -paren_args : '(' opt_call_args rparen - { - $$ = $2; - } - ; - -opt_paren_args : none - | paren_args - ; - -opt_call_args : none - | call_args - | args ',' - { - $$ = cons($1,0); - NODE_LINENO($$, $1); - } - | args ',' assocs ',' - { - $$ = cons(push($1, new_hash(p, $3)), 0); - NODE_LINENO($$, $1); - } - | assocs ',' - { - $$ = cons(list1(new_hash(p, $1)), 0); - NODE_LINENO($$, $1); - } - ; - -call_args : command - { - $$ = cons(list1($1), 0); - NODE_LINENO($$, $1); - } - | args opt_block_arg - { - $$ = cons($1, $2); - NODE_LINENO($$, $1); - } - | assocs opt_block_arg - { - $$ = cons(list1(new_hash(p, $1)), $2); - NODE_LINENO($$, $1); - } - | args ',' assocs opt_block_arg - { - $$ = cons(push($1, new_hash(p, $3)), $4); - NODE_LINENO($$, $1); - } - | block_arg - { - $$ = cons(0, $1); - NODE_LINENO($$, $1); - } - ; - -command_args : { - $$ = p->cmdarg_stack; - CMDARG_PUSH(1); - } - call_args - { - p->cmdarg_stack = $1; - $$ = $2; - } - ; - -block_arg : tAMPER arg_value - { - $$ = new_block_arg(p, $2); - } - ; - -opt_block_arg : ',' block_arg - { - $$ = $2; - } - | none - { - $$ = 0; - } - ; - -args : arg_value - { - $$ = cons($1, 0); - NODE_LINENO($$, $1); - } - | tSTAR arg_value - { - $$ = cons(new_splat(p, $2), 0); - NODE_LINENO($$, $2); - } - | args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - | args ',' heredoc_bodies arg_value - { - $$ = push($1, $4); - } - | args ',' heredoc_bodies tSTAR arg_value - { - $$ = push($1, new_splat(p, $5)); - } - ; - -mrhs : args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - | tSTAR arg_value - { - $$ = list1(new_splat(p, $2)); - } - ; - -primary : literal - | string - | xstring - | regexp - | heredoc - | var_ref - | backref - | tFID - { - $$ = new_fcall(p, $1, 0); - } - | keyword_begin - { - $$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - bodystmt - keyword_end - { - p->cmdarg_stack = $2; - $$ = $3; - } - | tLPAREN_ARG - { - $$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - expr {p->lstate = EXPR_ENDARG;} rparen - { - p->cmdarg_stack = $2; - $$ = $3; - } - | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen - { - $$ = 0; - } - | tLPAREN compstmt ')' - { - $$ = $2; - } - | primary_value tCOLON2 tCONSTANT - { - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - $$ = new_colon3(p, $2); - } - | tLBRACK aref_args ']' - { - $$ = new_array(p, $2); - NODE_LINENO($$, $2); - } - | tLBRACE assoc_list '}' - { - $$ = new_hash(p, $2); - NODE_LINENO($$, $2); - } - | keyword_return - { - $$ = new_return(p, 0); - } - | keyword_yield '(' call_args rparen - { - $$ = new_yield(p, $3); - } - | keyword_yield '(' rparen - { - $$ = new_yield(p, 0); - } - | keyword_yield - { - $$ = new_yield(p, 0); - } - | keyword_not '(' expr rparen - { - $$ = call_uni_op(p, cond($3), "!"); - } - | keyword_not '(' rparen - { - $$ = call_uni_op(p, new_nil(p), "!"); - } - | operation brace_block - { - $$ = new_fcall(p, $1, cons(0, $2)); - } - | method_call - | method_call brace_block - { - call_with_block(p, $1, $2); - $$ = $1; - } - | tLAMBDA - { - local_nest(p); - $$ = p->lpar_beg; - p->lpar_beg = ++p->paren_nest; - } - f_larglist - { - $$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - lambda_body - { - p->lpar_beg = $2; - $$ = new_lambda(p, $3, $5); - local_unnest(p); - p->cmdarg_stack = $4; - } - | keyword_if expr_value then - compstmt - if_tail - keyword_end - { - $$ = new_if(p, cond($2), $4, $5); - SET_LINENO($$, $1); - } - | keyword_unless expr_value then - compstmt - opt_else - keyword_end - { - $$ = new_unless(p, cond($2), $4, $5); - SET_LINENO($$, $1); - } - | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_while(p, cond($3), $6); - SET_LINENO($$, $1); - } - | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_until(p, cond($3), $6); - SET_LINENO($$, $1); - } - | keyword_case expr_value opt_terms - case_body - keyword_end - { - $$ = new_case(p, $2, $4); - } - | keyword_case opt_terms case_body keyword_end - { - $$ = new_case(p, 0, $3); - } - | keyword_for for_var keyword_in - {COND_PUSH(1);} - expr_value do - {COND_POP();} - compstmt - keyword_end - { - $$ = new_for(p, $2, $5, $8); - SET_LINENO($$, $1); - } - | keyword_class - cpath superclass - { - if (p->in_def || p->in_single) - yyerror(p, "class definition in method body"); - $$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_class(p, $2, $3, $5); - SET_LINENO($$, $1); - local_resume(p, $4); - } - | keyword_class - tLSHFT expr - { - $$ = p->in_def; - p->in_def = 0; - } - term - { - $$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); - p->in_single = 0; - } - bodystmt - keyword_end - { - $$ = new_sclass(p, $3, $7); - SET_LINENO($$, $1); - local_resume(p, $6->car); - p->in_def = $4; - p->in_single = (int)(intptr_t)$6->cdr; - } - | keyword_module - cpath - { - if (p->in_def || p->in_single) - yyerror(p, "module definition in method body"); - $$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_module(p, $2, $4); - SET_LINENO($$, $1); - local_resume(p, $3); - } - | keyword_def fname - { - $$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - { - p->in_def++; - $$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_def(p, $2, $5, $6); - SET_LINENO($$, $1); - local_resume(p, $4); - p->in_def--; - p->cmdarg_stack = $3; - } - | keyword_def singleton dot_or_colon - { - p->lstate = EXPR_FNAME; - $$ = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - fname - { - p->in_single++; - p->lstate = EXPR_ENDFN; /* force for args */ - $$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_sdef(p, $2, $5, $7, $8); - SET_LINENO($$, $1); - local_resume(p, $6); - p->in_single--; - p->cmdarg_stack = $4; - } - | keyword_break - { - $$ = new_break(p, 0); - } - | keyword_next - { - $$ = new_next(p, 0); - } - | keyword_redo - { - $$ = new_redo(p); - } - | keyword_retry - { - $$ = new_retry(p); - } - ; - -primary_value : primary - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -then : term - | keyword_then - | term keyword_then - ; - -do : term - | keyword_do_cond - ; - -if_tail : opt_else - | keyword_elsif expr_value then - compstmt - if_tail - { - $$ = new_if(p, cond($2), $4, $5); - } - ; - -opt_else : none - | keyword_else compstmt - { - $$ = $2; - } - ; - -for_var : lhs - { - $$ = list1(list1($1)); - } - | mlhs - ; - -f_marg : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_marg_list : f_marg - { - $$ = list1($1); - } - | f_marg_list ',' f_marg - { - $$ = push($1, $3); - } - ; - -f_margs : f_marg_list - { - $$ = list3($1,0,0); - } - | f_marg_list ',' tSTAR f_norm_arg - { - $$ = list3($1, new_arg(p, $4), 0); - } - | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3($1, new_arg(p, $4), $6); - } - | f_marg_list ',' tSTAR - { - $$ = list3($1, (node*)-1, 0); - } - | f_marg_list ',' tSTAR ',' f_marg_list - { - $$ = list3($1, (node*)-1, $5); - } - | tSTAR f_norm_arg - { - $$ = list3(0, new_arg(p, $2), 0); - } - | tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3(0, new_arg(p, $2), $4); - } - | tSTAR - { - $$ = list3(0, (node*)-1, 0); - } - | tSTAR ',' f_marg_list - { - $$ = list3(0, (node*)-1, $3); - } - ; - -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_block_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' - { - $$ = new_args(p, $1, 0, 1, 0, 0); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_block_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - ; - -opt_block_param : none - | block_param_def - { - p->cmd_start = TRUE; - $$ = $1; - } - ; - -block_param_def : '|' opt_bv_decl '|' - { - $$ = 0; - } - | tOROP - { - $$ = 0; - } - | '|' block_param opt_bv_decl '|' - { - $$ = $2; - } - ; - - -opt_bv_decl : opt_nl - { - $$ = 0; - } - | opt_nl ';' bv_decls opt_nl - { - $$ = 0; - } - ; - -bv_decls : bvar - | bv_decls ',' bvar - ; - -bvar : tIDENTIFIER - { - local_add_f(p, $1); - new_bv(p, $1); - } - | f_bad_arg - ; - -f_larglist : '(' f_args opt_bv_decl ')' - { - $$ = $2; - } - | f_args - { - $$ = $1; - } - ; - -lambda_body : tLAMBEG compstmt '}' - { - $$ = $2; - } - | keyword_do_LAMBDA compstmt keyword_end - { - $$ = $2; - } - ; - -do_block : keyword_do_block - { - local_nest(p); - } - opt_block_param - compstmt - keyword_end - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - ; - -block_call : command do_block - { - if ($1->car == (node*)NODE_YIELD) { - yyerror(p, "block given to yield"); - } - else { - call_with_block(p, $1, $2); - } - $$ = $1; - } - | block_call dot_or_colon operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | block_call dot_or_colon operation2 opt_paren_args brace_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - | block_call dot_or_colon operation2 command_args do_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - ; - -method_call : operation paren_args - { - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation3 - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' paren_args - { - $$ = new_call(p, $1, intern("call",4), $3); - } - | primary_value tCOLON2 paren_args - { - $$ = new_call(p, $1, intern("call",4), $3); - } - | keyword_super paren_args - { - $$ = new_super(p, $2); - } - | keyword_super - { - $$ = new_zsuper(p); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern("[]",2), $3); - } - ; - -brace_block : '{' - { - local_nest(p); - $$ = p->lineno; - } - opt_block_param - compstmt '}' - { - $$ = new_block(p,$3,$4); - SET_LINENO($$, $2); - local_unnest(p); - } - | keyword_do - { - local_nest(p); - $$ = p->lineno; - } - opt_block_param - compstmt keyword_end - { - $$ = new_block(p,$3,$4); - SET_LINENO($$, $2); - local_unnest(p); - } - ; - -case_body : keyword_when args then - compstmt - cases - { - $$ = cons(cons($2, $4), $5); - } - ; - -cases : opt_else - { - if ($1) { - $$ = cons(cons(0, $1), 0); - } - else { - $$ = 0; - } - } - | case_body - ; - -opt_rescue : keyword_rescue exc_list exc_var then - compstmt - opt_rescue - { - $$ = list1(list3($2, $3, $5)); - if ($6) $$ = append($$, $6); - } - | none - ; - -exc_list : arg_value - { - $$ = list1($1); - } - | mrhs - | none - ; - -exc_var : tASSOC lhs - { - $$ = $2; - } - | none - ; - -opt_ensure : keyword_ensure compstmt - { - $$ = $2; - } - | none - ; - -literal : numeric - | symbol - | words - | symbols - ; - -string : tCHAR - | tSTRING - | tSTRING_BEG tSTRING - { - $$ = $2; - } - | tSTRING_BEG string_rep tSTRING - { - $$ = new_dstr(p, push($2, $3)); - } - ; - -string_rep : string_interp - | string_rep string_interp - { - $$ = append($1, $2); - } - ; - -string_interp : tSTRING_MID - { - $$ = list1($1); - } - | tSTRING_PART - { - $$ = p->lex_strterm; - p->lex_strterm = NULL; - } - compstmt - '}' - { - p->lex_strterm = $2; - $$ = list2($1, $3); - } - | tLITERAL_DELIM - { - $$ = list1(new_literal_delim(p)); - } - | tHD_LITERAL_DELIM heredoc_bodies - { - $$ = list1(new_literal_delim(p)); - } - ; - -xstring : tXSTRING_BEG tXSTRING - { - $$ = $2; - } - | tXSTRING_BEG string_rep tXSTRING - { - $$ = new_dxstr(p, push($2, $3)); - } - ; - -regexp : tREGEXP_BEG tREGEXP - { - $$ = $2; - } - | tREGEXP_BEG string_rep tREGEXP - { - $$ = new_dregx(p, $2, $3); - } - ; - -heredoc : tHEREDOC_BEG - ; - -opt_heredoc_bodies : /* none */ - | heredoc_bodies - ; - -heredoc_bodies : heredoc_body - | heredoc_bodies heredoc_body - ; - -heredoc_body : tHEREDOC_END - { - parser_heredoc_info * inf = parsing_heredoc_inf(p); - inf->doc = push(inf->doc, new_str(p, "", 0)); - heredoc_end(p); - } - | heredoc_string_rep tHEREDOC_END - { - heredoc_end(p); - } - ; - -heredoc_string_rep : heredoc_string_interp - | heredoc_string_rep heredoc_string_interp - ; - -heredoc_string_interp : tHD_STRING_MID - { - parser_heredoc_info * inf = parsing_heredoc_inf(p); - inf->doc = push(inf->doc, $1); - heredoc_treat_nextline(p); - } - | tHD_STRING_PART - { - $$ = p->lex_strterm; - p->lex_strterm = NULL; - } - compstmt - '}' - { - parser_heredoc_info * inf = parsing_heredoc_inf(p); - p->lex_strterm = $2; - inf->doc = push(push(inf->doc, $1), $3); - } - ; - -words : tWORDS_BEG tSTRING - { - $$ = new_words(p, list1($2)); - } - | tWORDS_BEG string_rep tSTRING - { - $$ = new_words(p, push($2, $3)); - } - ; - - -symbol : basic_symbol - { - $$ = new_sym(p, $1); - } - | tSYMBEG tSTRING_BEG string_interp tSTRING - { - p->lstate = EXPR_END; - $$ = new_dsym(p, push($3, $4)); - } - ; - -basic_symbol : tSYMBEG sym - { - p->lstate = EXPR_END; - $$ = $2; - } - ; - -sym : fname - | tIVAR - | tGVAR - | tCVAR - | tSTRING - { - $$ = new_strsym(p, $1); - } - | tSTRING_BEG tSTRING - { - $$ = new_strsym(p, $2); - } - ; - -symbols : tSYMBOLS_BEG tSTRING - { - $$ = new_symbols(p, list1($2)); - } - | tSYMBOLS_BEG string_rep tSTRING - { - $$ = new_symbols(p, push($2, $3)); - } - ; - -numeric : tINTEGER - | tFLOAT - | tUMINUS_NUM tINTEGER %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - | tUMINUS_NUM tFLOAT %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - ; - -variable : tIDENTIFIER - { - $$ = new_lvar(p, $1); - } - | tIVAR - { - $$ = new_ivar(p, $1); - } - | tGVAR - { - $$ = new_gvar(p, $1); - } - | tCVAR - { - $$ = new_cvar(p, $1); - } - | tCONSTANT - { - $$ = new_const(p, $1); - } - ; - -var_lhs : variable - { - assignable(p, $1); - } - ; - -var_ref : variable - { - $$ = var_reference(p, $1); - } - | keyword_nil - { - $$ = new_nil(p); - } - | keyword_self - { - $$ = new_self(p); - } - | keyword_true - { - $$ = new_true(p); - } - | keyword_false - { - $$ = new_false(p); - } - | keyword__FILE__ - { - if (!p->filename) { - p->filename = "(null)"; - } - $$ = new_str(p, p->filename, strlen(p->filename)); - } - | keyword__LINE__ - { - char buf[16]; - - snprintf(buf, sizeof(buf), "%d", p->lineno); - $$ = new_int(p, buf, 10); - } - ; - -backref : tNTH_REF - | tBACK_REF - ; - -superclass : term - { - $$ = 0; - } - | '<' - { - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - expr_value term - { - $$ = $3; - } - | error term - { - yyerrok; - $$ = 0; - } - ; - -f_arglist : '(' f_args rparen - { - $$ = $2; - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - | f_args term - { - $$ = $1; - } - ; - -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - | /* none */ - { - local_add_f(p, 0); - $$ = new_args(p, 0, 0, 0, 0, 0); - } - ; - -f_bad_arg : tCONSTANT - { - yyerror(p, "formal argument cannot be a constant"); - $$ = 0; - } - | tIVAR - { - yyerror(p, "formal argument cannot be an instance variable"); - $$ = 0; - } - | tGVAR - { - yyerror(p, "formal argument cannot be a global variable"); - $$ = 0; - } - | tCVAR - { - yyerror(p, "formal argument cannot be a class variable"); - $$ = 0; - } - ; - -f_norm_arg : f_bad_arg - { - $$ = 0; - } - | tIDENTIFIER - { - local_add_f(p, $1); - $$ = $1; - } - ; - -f_arg_item : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_arg : f_arg_item - { - $$ = list1($1); - } - | f_arg ',' f_arg_item - { - $$ = push($1, $3); - } - ; - -f_opt_asgn : tIDENTIFIER '=' - { - local_add_f(p, $1); - $$ = $1; - } - ; - -f_opt : f_opt_asgn arg_value - { - $$ = cons(nsym($1), $2); - } - ; - -f_block_opt : f_opt_asgn primary_value - { - $$ = cons(nsym($1), $2); - } - ; - -f_block_optarg : f_block_opt - { - $$ = list1($1); - } - | f_block_optarg ',' f_block_opt - { - $$ = push($1, $3); - } - ; - -f_optarg : f_opt - { - $$ = list1($1); - } - | f_optarg ',' f_opt - { - $$ = push($1, $3); - } - ; - -restarg_mark : '*' - | tSTAR - ; - -f_rest_arg : restarg_mark tIDENTIFIER - { - local_add_f(p, $2); - $$ = $2; - } - | restarg_mark - { - local_add_f(p, 0); - $$ = -1; - } - ; - -blkarg_mark : '&' - | tAMPER - ; - -f_block_arg : blkarg_mark tIDENTIFIER - { - local_add_f(p, $2); - $$ = $2; - } - ; - -opt_f_block_arg : ',' f_block_arg - { - $$ = $2; - } - | none - { - local_add_f(p, 0); - $$ = 0; - } - ; - -singleton : var_ref - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - | '(' {p->lstate = EXPR_BEG;} expr rparen - { - if ($3 == 0) { - yyerror(p, "can't define singleton method for ()."); - } - else { - switch ((enum node_type)(int)(intptr_t)$3->car) { - case NODE_STR: - case NODE_DSTR: - case NODE_XSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_MATCH: - case NODE_FLOAT: - case NODE_ARRAY: - case NODE_HEREDOC: - yyerror(p, "can't define singleton method for literals"); - default: - break; - } - } - $$ = $3; - } - ; - -assoc_list : none - | assocs trailer - { - $$ = $1; - } - ; - -assocs : assoc - { - $$ = list1($1); - NODE_LINENO($$, $1); - } - | assocs ',' assoc - { - $$ = push($1, $3); - } - ; - -assoc : arg_value tASSOC arg_value - { - $$ = cons($1, $3); - } - | tLABEL arg_value - { - $$ = cons(new_sym(p, $1), $2); - } - ; - -operation : tIDENTIFIER - | tCONSTANT - | tFID - ; - -operation2 : tIDENTIFIER - | tCONSTANT - | tFID - | op - ; - -operation3 : tIDENTIFIER - | tFID - | op - ; - -dot_or_colon : '.' - | tCOLON2 - ; - -opt_terms : /* none */ - | terms - ; - -opt_nl : /* none */ - | nl - ; - -rparen : opt_nl ')' - ; - -rbracket : opt_nl ']' - ; - -trailer : /* none */ - | nl - | ',' - ; - -term : ';' {yyerrok;} - | nl - ; - -nl : '\n' - { - p->lineno++; - p->column = 0; - } - opt_heredoc_bodies - -terms : term - | terms ';' {yyerrok;} - ; - -none : /* none */ - { - $$ = 0; - } - ; -%% -#define yylval (*((YYSTYPE*)(p->ylval))) - -static void -yyerror(parser_state *p, const char *s) -{ - char* c; - int n; - - if (! p->capture_errors) { -#ifdef ENABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); - } - else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); - } -#endif - } - else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) { - n = strlen(s); - c = (char *)parser_palloc(p, n + 1); - memcpy(c, s, n + 1); - p->error_buffer[p->nerr].message = c; - p->error_buffer[p->nerr].lineno = p->lineno; - p->error_buffer[p->nerr].column = p->column; - } - p->nerr++; -} - -static void -yyerror_i(parser_state *p, const char *fmt, int i) -{ - char buf[256]; - - snprintf(buf, sizeof(buf), fmt, i); - yyerror(p, buf); -} - -static void -yywarn(parser_state *p, const char *s) -{ - char* c; - int n; - - if (! p->capture_errors) { -#ifdef ENABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); - } - else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); - } -#endif - } - else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) { - n = strlen(s); - c = (char *)parser_palloc(p, n + 1); - memcpy(c, s, n + 1); - p->warn_buffer[p->nwarn].message = c; - p->warn_buffer[p->nwarn].lineno = p->lineno; - p->warn_buffer[p->nwarn].column = p->column; - } - p->nwarn++; -} - -static void -yywarning(parser_state *p, const char *s) -{ - yywarn(p, s); -} - -static void -yywarning_s(parser_state *p, const char *fmt, const char *s) -{ - char buf[256]; - - snprintf(buf, sizeof(buf), fmt, s); - yywarning(p, buf); -} - -static void -backref_error(parser_state *p, node *n) -{ - int c; - - c = (int)(intptr_t)n->car; - - if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr); - } - else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); - } - else { - mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); - } -} - -static void pushback(parser_state *p, int c); -static mrb_bool peeks(parser_state *p, const char *s); -static mrb_bool skips(parser_state *p, const char *s); - -static inline int -nextc(parser_state *p) -{ - int c; - - if (p->pb) { - node *tmp; - - c = (int)(intptr_t)p->pb->car; - tmp = p->pb; - p->pb = p->pb->cdr; - cons_free(tmp); - } - else { -#ifdef ENABLE_STDIO - if (p->f) { - if (feof(p->f)) goto eof; - c = fgetc(p->f); - if (c == EOF) goto eof; - } - else -#endif - if (!p->s || p->s >= p->send) { - goto eof; - } - else { - c = (unsigned char)*p->s++; - } - } - if (c >= 0) { - p->column++; - } - if (c == '\r') { - c = nextc(p); - if (c != '\n') { - pushback(p, c); - return '\r'; - } - return c; - } - return c; - - eof: - if (!p->cxt) return -1; - else { - if (p->cxt->partial_hook(p) < 0) - return -1; /* end of program(s) */ - return -2; /* end of a file in the program files */ - } -} - -static void -pushback(parser_state *p, int c) -{ - if (c >= 0) { - p->column--; - } - p->pb = cons((node*)(intptr_t)c, p->pb); -} - -static void -skip(parser_state *p, char term) -{ - int c; - - for (;;) { - c = nextc(p); - if (c < 0) break; - if (c == term) break; - } -} - -static int -peekc_n(parser_state *p, int n) -{ - node *list = 0; - int c0; - - do { - c0 = nextc(p); - if (c0 == -1) return c0; /* do not skip partial EOF */ - list = push(list, (node*)(intptr_t)c0); - } while(n--); - if (p->pb) { - p->pb = append((node*)list, p->pb); - } - else { - p->pb = list; - } - return c0; -} - -static mrb_bool -peek_n(parser_state *p, int c, int n) -{ - return peekc_n(p, n) == c && c >= 0; -} -#define peek(p,c) peek_n((p), (c), 0) - -static mrb_bool -peeks(parser_state *p, const char *s) -{ - int len = strlen(s); - -#ifdef ENABLE_STDIO - if (p->f) { - int n = 0; - while (*s) { - if (!peek_n(p, *s++, n++)) return FALSE; - } - return TRUE; - } - else -#endif - if (p->s && p->s + len <= p->send) { - if (memcmp(p->s, s, len) == 0) return TRUE; - } - return FALSE; -} - -static mrb_bool -skips(parser_state *p, const char *s) -{ - int c; - - for (;;) { - /* skip until first char */ - for (;;) { - c = nextc(p); - if (c < 0) return c; - if (c == '\n') { - p->lineno++; - p->column = 0; - } - if (c == *s) break; - } - s++; - if (peeks(p, s)) { - int len = strlen(s); - - while (len--) { - if (nextc(p) == '\n') { - p->lineno++; - p->column = 0; - } - } - return TRUE; - } - else{ - s--; - } - } - return FALSE; -} - - -static int -newtok(parser_state *p) -{ - p->bidx = 0; - return p->column - 1; -} - -static void -tokadd(parser_state *p, int32_t c) -{ - char utf8[4]; - unsigned len; - - /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */ - if (c >= 0) { - /* Single byte from source or non-Unicode escape */ - utf8[0] = (char)c; - len = 1; - } - else { - /* Unicode character */ - c = -c; - if (c < 0x80) { - utf8[0] = (char)c; - len = 1; - } - else if (c < 0x800) { - utf8[0] = (char)(0xC0 | (c >> 6)); - utf8[1] = (char)(0x80 | (c & 0x3F)); - len = 2; - } - else if (c < 0x10000) { - utf8[0] = (char)(0xE0 | (c >> 12) ); - utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); - utf8[2] = (char)(0x80 | ( c & 0x3F)); - len = 3; - } - else { - utf8[0] = (char)(0xF0 | (c >> 18) ); - utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); - utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); - utf8[3] = (char)(0x80 | ( c & 0x3F)); - len = 4; - } - } - if (p->bidx+len <= MRB_PARSER_BUF_SIZE) { - unsigned i; - for (i = 0; i < len; i++) { - p->buf[p->bidx++] = utf8[i]; - } - } -} - -static int -toklast(parser_state *p) -{ - return p->buf[p->bidx-1]; -} - -static void -tokfix(parser_state *p) -{ - if (p->bidx >= MRB_PARSER_BUF_SIZE) { - yyerror(p, "string too long (truncated)"); - } - p->buf[p->bidx] = '\0'; -} - -static const char* -tok(parser_state *p) -{ - return p->buf; -} - -static int -toklen(parser_state *p) -{ - return p->bidx; -} - -#define IS_ARG() (p->lstate == EXPR_ARG || p->lstate == EXPR_CMDARG) -#define IS_END() (p->lstate == EXPR_END || p->lstate == EXPR_ENDARG || p->lstate == EXPR_ENDFN) -#define IS_BEG() (p->lstate == EXPR_BEG || p->lstate == EXPR_MID || p->lstate == EXPR_VALUE || p->lstate == EXPR_CLASS) -#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c)) -#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG()) -#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1)) - -static int -scan_oct(const int *start, int len, int *retlen) -{ - const int *s = start; - int retval = 0; - - /* mrb_assert(len <= 3) */ - while (len-- && *s >= '0' && *s <= '7') { - retval <<= 3; - retval |= *s++ - '0'; - } - *retlen = s - start; - - return retval; -} - -static int32_t -scan_hex(const int *start, int len, int *retlen) -{ - static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; - const int *s = start; - int32_t retval = 0; - char *tmp; - - /* mrb_assert(len <= 8) */ - while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { - retval <<= 4; - retval |= (tmp - hexdigit) & 15; - s++; - } - *retlen = s - start; - - return retval; -} - -/* Return negative to indicate Unicode code point */ -static int32_t -read_escape(parser_state *p) -{ - int32_t c; - - switch (c = nextc(p)) { - case '\\':/* Backslash */ - return c; - - case 'n':/* newline */ - return '\n'; - - case 't':/* horizontal tab */ - return '\t'; - - case 'r':/* carriage-return */ - return '\r'; - - case 'f':/* form-feed */ - return '\f'; - - case 'v':/* vertical tab */ - return '\13'; - - case 'a':/* alarm(bell) */ - return '\007'; - - case 'e':/* escape */ - return 033; - - case '0': case '1': case '2': case '3': /* octal constant */ - case '4': case '5': case '6': case '7': - { - int buf[3]; - int i; - - buf[0] = c; - for (i=1; i<3; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (buf[i] < '0' || '7' < buf[i]) { - pushback(p, buf[i]); - break; - } - } - c = scan_oct(buf, i, &i); - } - return c; - - case 'x': /* hex constant */ - { - int buf[2]; - int i; - - for (i=0; i<2; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (!ISXDIGIT(buf[i])) { - pushback(p, buf[i]); - break; - } - } - c = scan_hex(buf, i, &i); - if (i == 0) { - yyerror(p, "Invalid escape character syntax"); - return 0; - } - } - return c; - - case 'u': /* Unicode */ - { - int buf[9]; - int i; - - /* Look for opening brace */ - i = 0; - buf[0] = nextc(p); - if (buf[0] < 0) goto eof; - if (buf[0] == '{') { - /* \u{xxxxxxxx} form */ - for (i=0; i<9; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (buf[i] == '}') { - break; - } - else if (!ISXDIGIT(buf[i])) { - yyerror(p, "Invalid escape character syntax"); - pushback(p, buf[i]); - return 0; - } - } - } - else if (ISXDIGIT(buf[0])) { - /* \uxxxx form */ - for (i=1; i<4; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (!ISXDIGIT(buf[i])) { - pushback(p, buf[i]); - break; - } - } - } - else { - pushback(p, buf[0]); - } - c = scan_hex(buf, i, &i); - if (i == 0) { - yyerror(p, "Invalid escape character syntax"); - return 0; - } - if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { - yyerror(p, "Invalid Unicode code point"); - return 0; - } - } - return -c; - - case 'b':/* backspace */ - return '\010'; - - case 's':/* space */ - return ' '; - - case 'M': - if ((c = nextc(p)) != '-') { - yyerror(p, "Invalid escape character syntax"); - pushback(p, c); - return '\0'; - } - if ((c = nextc(p)) == '\\') { - return read_escape(p) | 0x80; - } - else if (c < 0) goto eof; - else { - return ((c & 0xff) | 0x80); - } - - case 'C': - if ((c = nextc(p)) != '-') { - yyerror(p, "Invalid escape character syntax"); - pushback(p, c); - return '\0'; - } - case 'c': - if ((c = nextc(p))== '\\') { - c = read_escape(p); - } - else if (c == '?') - return 0177; - else if (c < 0) goto eof; - return c & 0x9f; - - eof: - case -1: - case -2: /* end of a file */ - yyerror(p, "Invalid escape character syntax"); - return '\0'; - - default: - return c; - } -} - -static int -parse_string(parser_state *p) -{ - int c; - string_type type = (string_type)(intptr_t)p->lex_strterm->car; - int nest_level = (intptr_t)p->lex_strterm->cdr->car; - int beg = (intptr_t)p->lex_strterm->cdr->cdr->car; - int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr; - parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL; - - newtok(p); - while ((c = nextc(p)) != end || nest_level != 0) { - if (hinf && (c == '\n' || c < 0)) { - mrb_bool line_head; - tokadd(p, '\n'); - tokfix(p); - p->lineno++; - p->column = 0; - line_head = hinf->line_head; - hinf->line_head = TRUE; - if (line_head) { - /* check whether end of heredoc */ - const char *s = tok(p); - int len = toklen(p); - if (hinf->allow_indent) { - while (ISSPACE(*s) && len > 0) { - ++s; - --len; - } - } - if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { - return tHEREDOC_END; - } - } - if (c < 0) { - char buf[256]; - snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); - yyerror(p, buf); - return 0; - } - yylval.nd = new_str(p, tok(p), toklen(p)); - return tHD_STRING_MID; - } - if (c < 0) { - yyerror(p, "unterminated string meets end of file"); - return 0; - } - else if (c == beg) { - nest_level++; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; - } - else if (c == end) { - nest_level--; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; - } - else if (c == '\\') { - c = nextc(p); - if (type & STR_FUNC_EXPAND) { - if (c == end || c == beg) { - tokadd(p, c); - } - else if (c == '\n') { - p->lineno++; - p->column = 0; - if (type & STR_FUNC_ARRAY) { - tokadd(p, '\n'); - } - } - else if (type & STR_FUNC_REGEXP) { - tokadd(p, '\\'); - tokadd(p, c); - } - else { - pushback(p, c); - tokadd(p, read_escape(p)); - if (hinf) - hinf->line_head = FALSE; - } - } - else { - if (c != beg && c != end) { - if (c == '\n') { - p->lineno++; - p->column = 0; - } - if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) { - tokadd(p, '\\'); - } - } - tokadd(p, c); - } - continue; - } - else if ((c == '#') && (type & STR_FUNC_EXPAND)) { - c = nextc(p); - if (c == '{') { - tokfix(p); - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - yylval.nd = new_str(p, tok(p), toklen(p)); - if (hinf) { - hinf->line_head = FALSE; - return tHD_STRING_PART; - } - return tSTRING_PART; - } - tokadd(p, '#'); - pushback(p, c); - continue; - } - if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { - if (toklen(p) == 0) { - do { - if (c == '\n') { - p->lineno++; - p->column = 0; - heredoc_treat_nextline(p); - if (p->parsing_heredoc != NULL) { - return tHD_LITERAL_DELIM; - } - } - c = nextc(p); - } while (ISSPACE(c)); - pushback(p, c); - return tLITERAL_DELIM; - } - else { - pushback(p, c); - tokfix(p); - yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING_MID; - } - } - tokadd(p, c); - } - - tokfix(p); - p->lstate = EXPR_END; - end_strterm(p); - - if (type & STR_FUNC_XQUOTE) { - yylval.nd = new_xstr(p, tok(p), toklen(p)); - return tXSTRING; - } - - if (type & STR_FUNC_REGEXP) { - int f = 0; - int re_opt; - char *s = strndup(tok(p), toklen(p)); - char flags[3]; - char *flag = flags; - char *dup; - - newtok(p); - while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) { - switch (re_opt) { - case 'i': f |= 1; break; - case 'x': f |= 2; break; - case 'm': f |= 4; break; - default: tokadd(p, re_opt); break; - } - } - pushback(p, re_opt); - if (toklen(p)) { - char msg[128]; - tokfix(p); - snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); - yyerror(p, msg); - } - if (f != 0) { - if (f & 1) *flag++ = 'i'; - if (f & 2) *flag++ = 'x'; - if (f & 4) *flag++ = 'm'; - dup = strndup(flags, (size_t)(flag - flags)); - } - else { - dup = NULL; - } - yylval.nd = new_regx(p, s, dup); - - return tREGEXP; - } - - yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING; -} - - -static int -heredoc_identifier(parser_state *p) -{ - int c; - int type = str_heredoc; - mrb_bool indent = FALSE; - mrb_bool quote = FALSE; - node *newnode; - parser_heredoc_info *info; - - c = nextc(p); - if (ISSPACE(c) || c == '=') { - pushback(p, c); - return 0; - } - if (c == '-') { - indent = TRUE; - c = nextc(p); - } - if (c == '\'' || c == '"') { - int term = c; - if (c == '\'') - quote = TRUE; - newtok(p); - while ((c = nextc(p)) >= 0 && c != term) { - if (c == '\n') { - c = -1; - break; - } - tokadd(p, c); - } - if (c < 0) { - yyerror(p, "unterminated here document identifier"); - return 0; - } - } - else { - if (c < 0) { - return 0; /* missing here document identifier */ - } - if (! identchar(c)) { - pushback(p, c); - if (indent) pushback(p, '-'); - return 0; - } - newtok(p); - do { - tokadd(p, c); - } while ((c = nextc(p)) >= 0 && identchar(c)); - pushback(p, c); - } - tokfix(p); - newnode = new_heredoc(p); - info = (parser_heredoc_info*)newnode->cdr; - info->term = strndup(tok(p), toklen(p)); - info->term_len = toklen(p); - if (! quote) - type |= STR_FUNC_EXPAND; - info->type = (string_type)type; - info->allow_indent = indent; - info->line_head = TRUE; - info->doc = NULL; - p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode); - p->lstate = EXPR_END; - - yylval.nd = newnode; - return tHEREDOC_BEG; -} - -static int -arg_ambiguous(parser_state *p) -{ - yywarning(p, "ambiguous first argument; put parentheses or even spaces"); - return 1; -} - -#include "lex.def" - -static int -parser_yylex(parser_state *p) -{ - int32_t c; - int space_seen = 0; - int cmd_state; - enum mrb_lex_state_enum last_state; - int token_column; - - if (p->lex_strterm) { - if (is_strterm_type(p, STR_FUNC_HEREDOC)) { - if (p->parsing_heredoc != NULL) - return parse_string(p); - } - else - return parse_string(p); - } - cmd_state = p->cmd_start; - p->cmd_start = FALSE; - retry: - last_state = p->lstate; - switch (c = nextc(p)) { - case '\004': /* ^D */ - case '\032': /* ^Z */ - case '\0': /* NUL */ - case -1: /* end of script. */ - if (p->heredocs_from_nextline) - goto maybe_heredoc; - return 0; - - /* white spaces */ - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - goto retry; - - case '#': /* it's a comment */ - skip(p, '\n'); - /* fall through */ - case -2: /* end of a file */ - case '\n': - maybe_heredoc: - heredoc_treat_nextline(p); - switch (p->lstate) { - case EXPR_BEG: - case EXPR_FNAME: - case EXPR_DOT: - case EXPR_CLASS: - case EXPR_VALUE: - p->lineno++; - p->column = 0; - if (p->parsing_heredoc != NULL) { - if (p->lex_strterm) { - return parse_string(p); - } - } - goto retry; - default: - break; - } - if (p->parsing_heredoc != NULL) { - return '\n'; - } - while ((c = nextc(p))) { - switch (c) { - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - break; - case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); - pushback(p, '.'); - goto retry; - } - case -1: /* EOF */ - case -2: /* end of a file */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; - } - } - normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; - - case '*': - if ((c = nextc(p)) == '*') { - if ((c = nextc(p)) == '=') { - yylval.id = intern("**",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - c = tPOW; - } - else { - if (c == '=') { - yylval.id = intern_c('*'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - if (IS_SPCARG(c)) { - yywarning(p, "`*' interpreted as argument prefix"); - c = tSTAR; - } - else if (IS_BEG()) { - c = tSTAR; - } - else { - c = '*'; - } - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return c; - - case '!': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return '!'; - } - } - else { - p->lstate = EXPR_BEG; - } - if (c == '=') { - return tNEQ; - } - if (c == '~') { - return tNMATCH; - } - pushback(p, c); - return '!'; - - case '=': - if (p->column == 1) { - static const char begin[] = "begin"; - static const char end[] = "\n=end"; - if (peeks(p, begin)) { - c = peekc_n(p, sizeof(begin)-1); - if (c < 0 || ISSPACE(c)) { - do { - if (!skips(p, end)) { - yyerror(p, "embedded document meets end of file"); - return 0; - } - c = nextc(p); - } while (!(c < 0 || ISSPACE(c))); - if (c != '\n') skip(p, '\n'); - p->lineno++; - p->column = 0; - goto retry; - } - } - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - if ((c = nextc(p)) == '=') { - if ((c = nextc(p)) == '=') { - return tEQQ; - } - pushback(p, c); - return tEQ; - } - if (c == '~') { - return tMATCH; - } - else if (c == '>') { - return tASSOC; - } - pushback(p, c); - return '='; - - case '<': - c = nextc(p); - if (c == '<' && - p->lstate != EXPR_DOT && - p->lstate != EXPR_CLASS && - !IS_END() && - (!IS_ARG() || space_seen)) { - int token = heredoc_identifier(p); - if (token) - return token; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - if (p->lstate == EXPR_CLASS) { - p->cmd_start = TRUE; - } - } - if (c == '=') { - if ((c = nextc(p)) == '>') { - return tCMP; - } - pushback(p, c); - return tLEQ; - } - if (c == '<') { - if ((c = nextc(p)) == '=') { - yylval.id = intern("<<",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tLSHFT; - } - pushback(p, c); - return '<'; - - case '>': - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - if ((c = nextc(p)) == '=') { - return tGEQ; - } - if (c == '>') { - if ((c = nextc(p)) == '=') { - yylval.id = intern(">>",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tRSHFT; - } - pushback(p, c); - return '>'; - - case '"': - p->lex_strterm = new_strterm(p, str_dquote, '"', 0); - return tSTRING_BEG; - - case '\'': - p->lex_strterm = new_strterm(p, str_squote, '\'', 0); - return parse_string(p); - - case '`': - if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; - return '`'; - } - if (p->lstate == EXPR_DOT) { - if (cmd_state) - p->lstate = EXPR_CMDARG; - else - p->lstate = EXPR_ARG; - return '`'; - } - p->lex_strterm = new_strterm(p, str_xquote, '`', 0); - return tXSTRING_BEG; - - case '?': - if (IS_END()) { - p->lstate = EXPR_VALUE; - return '?'; - } - c = nextc(p); - if (c < 0) { - yyerror(p, "incomplete character syntax"); - return 0; - } - if (ISSPACE(c)) { - if (!IS_ARG()) { - int c2; - switch (c) { - case ' ': - c2 = 's'; - break; - case '\n': - c2 = 'n'; - break; - case '\t': - c2 = 't'; - break; - case '\v': - c2 = 'v'; - break; - case '\r': - c2 = 'r'; - break; - case '\f': - c2 = 'f'; - break; - default: - c2 = 0; - break; - } - if (c2) { - char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); - yyerror(p, buf); - } - } - ternary: - pushback(p, c); - p->lstate = EXPR_VALUE; - return '?'; - } - newtok(p); - /* need support UTF-8 if configured */ - if ((isalnum(c) || c == '_')) { - int c2 = nextc(p); - pushback(p, c2); - if ((isalnum(c2) || c2 == '_')) { - goto ternary; - } - } - if (c == '\\') { - c = read_escape(p); - tokadd(p, c); - } - else { - tokadd(p, c); - } - tokfix(p); - yylval.nd = new_str(p, tok(p), toklen(p)); - p->lstate = EXPR_END; - return tCHAR; - - case '&': - if ((c = nextc(p)) == '&') { - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '=') { - yylval.id = intern("&&",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tANDOP; - } - else if (c == '=') { - yylval.id = intern_c('&'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - if (IS_SPCARG(c)) { - yywarning(p, "`&' interpreted as argument prefix"); - c = tAMPER; - } - else if (IS_BEG()) { - c = tAMPER; - } - else { - c = '&'; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return c; - - case '|': - if ((c = nextc(p)) == '|') { - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '=') { - yylval.id = intern("||",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - return tOROP; - } - if (c == '=') { - yylval.id = intern_c('|'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '|'; - - case '+': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return tUPLUS; - } - pushback(p, c); - return '+'; - } - if (c == '=') { - yylval.id = intern_c('+'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { - p->lstate = EXPR_BEG; - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - c = '+'; - goto start_num; - } - return tUPLUS; - } - p->lstate = EXPR_BEG; - pushback(p, c); - return '+'; - - case '-': - c = nextc(p); - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if (c == '@') { - return tUMINUS; - } - pushback(p, c); - return '-'; - } - if (c == '=') { - yylval.id = intern_c('-'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (c == '>') { - p->lstate = EXPR_ENDFN; - return tLAMBDA; - } - if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { - p->lstate = EXPR_BEG; - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - return tUMINUS_NUM; - } - return tUMINUS; - } - p->lstate = EXPR_BEG; - pushback(p, c); - return '-'; - - case '.': - p->lstate = EXPR_BEG; - if ((c = nextc(p)) == '.') { - if ((c = nextc(p)) == '.') { - return tDOT3; - } - pushback(p, c); - return tDOT2; - } - pushback(p, c); - if (c >= 0 && ISDIGIT(c)) { - yyerror(p, "no . floating literal anymore; put 0 before dot"); - } - p->lstate = EXPR_DOT; - return '.'; - - start_num: - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int is_float, seen_point, seen_e, nondigit; - - is_float = seen_point = seen_e = nondigit = 0; - p->lstate = EXPR_END; - newtok(p); - if (c == '-' || c == '+') { - tokadd(p, c); - c = nextc(p); - } - if (c == '0') { -#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0) - int start = toklen(p); - c = nextc(p); - if (c == 'x' || c == 'X') { - /* hexadecimal */ - c = nextc(p); - if (c >= 0 && ISXDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISXDIGIT(c)) break; - nondigit = 0; - tokadd(p, tolower(c)); - } while ((c = nextc(p)) >= 0); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 16); - return tINTEGER; - } - if (c == 'b' || c == 'B') { - /* binary */ - c = nextc(p); - if (c == '0' || c == '1') { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c != '0' && c != '1') break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) >= 0); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 2); - return tINTEGER; - } - if (c == 'd' || c == 'D') { - /* decimal */ - c = nextc(p); - if (c >= 0 && ISDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISDIGIT(c)) break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) >= 0); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; - } - if (c == '_') { - /* 0_0 */ - goto octal_number; - } - if (c == 'o' || c == 'O') { - /* prefixed octal */ - c = nextc(p); - if (c < 0 || c == '_' || !ISDIGIT(c)) { - no_digits(); - } - } - if (c >= '0' && c <= '7') { - /* octal */ - octal_number: - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c < '0' || c > '9') break; - if (c > '7') goto invalid_octal; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) >= 0); - - if (toklen(p) > start) { - pushback(p, c); - tokfix(p); - if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 8); - return tINTEGER; - } - if (nondigit) { - pushback(p, c); - goto trailing_uc; - } - } - if (c > '7' && c <= '9') { - invalid_octal: - yyerror(p, "Invalid octal digit"); - } - else if (c == '.' || c == 'e' || c == 'E') { - tokadd(p, '0'); - } - else { - pushback(p, c); - yylval.nd = new_int(p, "0", 10); - return tINTEGER; - } - } - - for (;;) { - switch (c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - nondigit = 0; - tokadd(p, c); - break; - - case '.': - if (nondigit) goto trailing_uc; - if (seen_point || seen_e) { - goto decode_num; - } - else { - int c0 = nextc(p); - if (c0 < 0 || !ISDIGIT(c0)) { - pushback(p, c0); - goto decode_num; - } - c = c0; - } - tokadd(p, '.'); - tokadd(p, c); - is_float++; - seen_point++; - nondigit = 0; - break; - - case 'e': - case 'E': - if (nondigit) { - pushback(p, c); - c = nondigit; - goto decode_num; - } - if (seen_e) { - goto decode_num; - } - tokadd(p, c); - seen_e++; - is_float++; - nondigit = c; - c = nextc(p); - if (c != '-' && c != '+') continue; - tokadd(p, c); - nondigit = c; - break; - - case '_': /* `_' in number just ignored */ - if (nondigit) goto decode_num; - nondigit = c; - break; - - default: - goto decode_num; - } - c = nextc(p); - } - - decode_num: - pushback(p, c); - if (nondigit) { - trailing_uc: - yyerror_i(p, "trailing `%c' in number", nondigit); - } - tokfix(p); - if (is_float) { - double d; - char *endp; - - errno = 0; - d = strtod(tok(p), &endp); - if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); - } - else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); - errno = 0; - } - yylval.nd = new_float(p, tok(p)); - return tFLOAT; - } - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; - } - - case ')': - case ']': - p->paren_nest--; - case '}': - COND_LEXPOP(); - CMDARG_LEXPOP(); - if (c == ')') - p->lstate = EXPR_ENDFN; - else - p->lstate = EXPR_ENDARG; - return c; - - case ':': - c = nextc(p); - if (c == ':') { - if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { - p->lstate = EXPR_BEG; - return tCOLON3; - } - p->lstate = EXPR_DOT; - return tCOLON2; - } - if (IS_END() || ISSPACE(c)) { - pushback(p, c); - p->lstate = EXPR_BEG; - return ':'; - } - pushback(p, c); - p->lstate = EXPR_FNAME; - return tSYMBEG; - - case '/': - if (IS_BEG()) { - p->lex_strterm = new_strterm(p, str_regexp, '/', 0); - return tREGEXP_BEG; - } - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('/'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - pushback(p, c); - if (IS_SPCARG(c)) { - p->lex_strterm = new_strterm(p, str_regexp, '/', 0); - return tREGEXP_BEG; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return '/'; - - case '^': - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('^'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '^'; - - case ';': - p->lstate = EXPR_BEG; - return ';'; - - case ',': - p->lstate = EXPR_BEG; - return ','; - - case '~': - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - if ((c = nextc(p)) != '@') { - pushback(p, c); - } - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - return '~'; - - case '(': - if (IS_BEG()) { - c = tLPAREN; - } - else if (IS_SPCARG(-1)) { - c = tLPAREN_ARG; - } - p->paren_nest++; - COND_PUSH(0); - CMDARG_PUSH(0); - p->lstate = EXPR_BEG; - return c; - - case '[': - p->paren_nest++; - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - if ((c = nextc(p)) == ']') { - if ((c = nextc(p)) == '=') { - return tASET; - } - pushback(p, c); - return tAREF; - } - pushback(p, c); - return '['; - } - else if (IS_BEG()) { - c = tLBRACK; - } - else if (IS_ARG() && space_seen) { - c = tLBRACK; - } - p->lstate = EXPR_BEG; - COND_PUSH(0); - CMDARG_PUSH(0); - return c; - - case '{': - if (p->lpar_beg && p->lpar_beg == p->paren_nest) { - p->lstate = EXPR_BEG; - p->lpar_beg = 0; - p->paren_nest--; - COND_PUSH(0); - CMDARG_PUSH(0); - return tLAMBEG; - } - if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN) - c = '{'; /* block (primary) */ - else if (p->lstate == EXPR_ENDARG) - c = tLBRACE_ARG; /* block (expr) */ - else - c = tLBRACE; /* hash */ - COND_PUSH(0); - CMDARG_PUSH(0); - p->lstate = EXPR_BEG; - return c; - - case '\\': - c = nextc(p); - if (c == '\n') { - p->lineno++; - p->column = 0; - space_seen = 1; - goto retry; /* skip \\n */ - } - pushback(p, c); - return '\\'; - - case '%': - if (IS_BEG()) { - int term; - int paren; - - c = nextc(p); - quotation: - if (c < 0 || !ISALNUM(c)) { - term = c; - c = 'Q'; - } - else { - term = nextc(p); - if (isalnum(term)) { - yyerror(p, "unknown type of %string"); - return 0; - } - } - if (c < 0 || term < 0) { - yyerror(p, "unterminated quoted string meets end of file"); - return 0; - } - paren = term; - if (term == '(') term = ')'; - else if (term == '[') term = ']'; - else if (term == '{') term = '}'; - else if (term == '<') term = '>'; - else paren = 0; - - switch (c) { - case 'Q': - p->lex_strterm = new_strterm(p, str_dquote, term, paren); - return tSTRING_BEG; - - case 'q': - p->lex_strterm = new_strterm(p, str_squote, term, paren); - return parse_string(p); - - case 'W': - p->lex_strterm = new_strterm(p, str_dword, term, paren); - return tWORDS_BEG; - - case 'w': - p->lex_strterm = new_strterm(p, str_sword, term, paren); - return tWORDS_BEG; - - case 'x': - p->lex_strterm = new_strterm(p, str_xquote, term, paren); - return tXSTRING_BEG; - - case 'r': - p->lex_strterm = new_strterm(p, str_regexp, term, paren); - return tREGEXP_BEG; - - case 's': - p->lex_strterm = new_strterm(p, str_ssym, term, paren); - return tSYMBEG; - - case 'I': - p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); - return tSYMBOLS_BEG; - - case 'i': - p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); - return tSYMBOLS_BEG; - - default: - yyerror(p, "unknown type of %string"); - return 0; - } - } - if ((c = nextc(p)) == '=') { - yylval.id = intern_c('%'); - p->lstate = EXPR_BEG; - return tOP_ASGN; - } - if (IS_SPCARG(c)) { - goto quotation; - } - if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { - p->lstate = EXPR_ARG; - } - else { - p->lstate = EXPR_BEG; - } - pushback(p, c); - return '%'; - - case '$': - p->lstate = EXPR_END; - token_column = newtok(p); - c = nextc(p); - if (c < 0) { - yyerror(p, "incomplete global variable syntax"); - return 0; - } - switch (c) { - case '_': /* $_: last read line string */ - c = nextc(p); - if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ - tokadd(p, '$'); - tokadd(p, c); - break; - } - pushback(p, c); - c = '_'; - /* fall through */ - case '~': /* $~: match-data */ - case '*': /* $*: argv */ - case '$': /* $$: pid */ - case '?': /* $?: last status */ - case '!': /* $!: error string */ - case '@': /* $@: error position */ - case '/': /* $/: input record separator */ - case '\\': /* $\: output record separator */ - case ';': /* $;: field separator */ - case ',': /* $,: output field separator */ - case '.': /* $.: last read line number */ - case '=': /* $=: ignorecase */ - case ':': /* $:: load path */ - case '<': /* $<: reading filename */ - case '>': /* $>: default output handle */ - case '\"': /* $": already loaded files */ - tokadd(p, '$'); - tokadd(p, c); - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tGVAR; - - case '-': - tokadd(p, '$'); - tokadd(p, c); - c = nextc(p); - pushback(p, c); - gvar: - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tGVAR; - - case '&': /* $&: last match */ - case '`': /* $`: string before last match */ - case '\'': /* $': string after last match */ - case '+': /* $+: string matches last pattern */ - if (last_state == EXPR_FNAME) { - tokadd(p, '$'); - tokadd(p, c); - goto gvar; - } - yylval.nd = new_back_ref(p, c); - return tBACK_REF; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - do { - tokadd(p, c); - c = nextc(p); - } while (c >= 0 && isdigit(c)); - pushback(p, c); - if (last_state == EXPR_FNAME) goto gvar; - tokfix(p); - { - unsigned long n = strtoul(tok(p), NULL, 10); - if (n > INT_MAX) { - yyerror_i(p, "capture group index must be <= %d", INT_MAX); - return 0; - } - yylval.nd = new_nth_ref(p, (int)n); - } - return tNTH_REF; - - default: - if (!identchar(c)) { - pushback(p, c); - return '$'; - } - case '0': - tokadd(p, '$'); - } - break; - - case '@': - c = nextc(p); - token_column = newtok(p); - tokadd(p, '@'); - if (c == '@') { - tokadd(p, '@'); - c = nextc(p); - } - if (c < 0) { - if (p->bidx == 1) { - yyerror(p, "incomplete instance variable syntax"); - } - else { - yyerror(p, "incomplete class variable syntax"); - } - return 0; - } - else if (isdigit(c)) { - if (p->bidx == 1) { - yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); - } - else { - yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); - } - return 0; - } - if (!identchar(c)) { - pushback(p, c); - return '@'; - } - break; - - case '_': - token_column = newtok(p); - break; - - default: - if (!identchar(c)) { - yyerror_i(p, "Invalid char `\\x%02X' in expression", c); - goto retry; - } - - token_column = newtok(p); - break; - } - - do { - tokadd(p, c); - c = nextc(p); - if (c < 0) break; - } while (identchar(c)); - if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') && - strncmp(tok(p), "__END__", toklen(p)) == 0) - return -1; - - switch (tok(p)[0]) { - case '@': case '$': - pushback(p, c); - break; - default: - if ((c == '!' || c == '?') && !peek(p, '=')) { - tokadd(p, c); - } - else { - pushback(p, c); - } - } - tokfix(p); - { - int result = 0; - - switch (tok(p)[0]) { - case '$': - p->lstate = EXPR_END; - result = tGVAR; - break; - case '@': - p->lstate = EXPR_END; - if (tok(p)[1] == '@') - result = tCVAR; - else - result = tIVAR; - break; - - default: - if (toklast(p) == '!' || toklast(p) == '?') { - result = tFID; - } - else { - if (p->lstate == EXPR_FNAME) { - if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && - (!peek(p, '=') || (peek_n(p, '>', 1)))) { - result = tIDENTIFIER; - tokadd(p, c); - tokfix(p); - } - else { - pushback(p, c); - } - } - if (result == 0 && ISUPPER(tok(p)[0])) { - result = tCONSTANT; - } - else { - result = tIDENTIFIER; - } - } - - if (IS_LABEL_POSSIBLE()) { - if (IS_LABEL_SUFFIX(0)) { - p->lstate = EXPR_BEG; - nextc(p); - tokfix(p); - yylval.id = intern_cstr(tok(p)); - return tLABEL; - } - } - if (p->lstate != EXPR_DOT) { - const struct kwtable *kw; - - /* See if it is a reserved word. */ - kw = mrb_reserved_word(tok(p), toklen(p)); - if (kw) { - enum mrb_lex_state_enum state = p->lstate; - yylval.num = p->lineno; - p->lstate = kw->state; - if (state == EXPR_FNAME) { - yylval.id = intern_cstr(kw->name); - return kw->id[0]; - } - if (p->lstate == EXPR_BEG) { - p->cmd_start = TRUE; - } - if (kw->id[0] == keyword_do) { - if (p->lpar_beg && p->lpar_beg == p->paren_nest) { - p->lpar_beg = 0; - p->paren_nest--; - return keyword_do_LAMBDA; - } - if (COND_P()) return keyword_do_cond; - if (CMDARG_P() && state != EXPR_CMDARG) - return keyword_do_block; - if (state == EXPR_ENDARG || state == EXPR_BEG) - return keyword_do_block; - return keyword_do; - } - if (state == EXPR_BEG || state == EXPR_VALUE) - return kw->id[0]; - else { - if (kw->id[0] != kw->id[1]) - p->lstate = EXPR_BEG; - return kw->id[1]; - } - } - } - - if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) { - if (cmd_state) { - p->lstate = EXPR_CMDARG; - } - else { - p->lstate = EXPR_ARG; - } - } - else if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; - } - else { - p->lstate = EXPR_END; - } - } - { - mrb_sym ident = intern_cstr(tok(p)); - - yylval.id = ident; -#if 0 - if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) { - p->lstate = EXPR_END; - } -#endif - } - return result; - } -} - -static int -yylex(void *lval, parser_state *p) -{ - p->ylval = lval; - return parser_yylex(p); -} - -static void -parser_init_cxt(parser_state *p, mrbc_context *cxt) -{ - if (!cxt) return; - if (cxt->filename) mrb_parser_set_filename(p, cxt->filename); - if (cxt->lineno) p->lineno = cxt->lineno; - if (cxt->syms) { - int i; - - p->locals = cons(0,0); - for (i=0; islen; i++) { - local_add_f(p, cxt->syms[i]); - } - } - p->capture_errors = cxt->capture_errors; - p->no_optimize = cxt->no_optimize; - if (cxt->partial_hook) { - p->cxt = cxt; - } -} - -static void -parser_update_cxt(parser_state *p, mrbc_context *cxt) -{ - node *n, *n0; - int i = 0; - - if (!cxt) return; - if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; - n0 = n = p->tree->cdr->car; - while (n) { - i++; - n = n->cdr; - } - cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym)); - cxt->slen = i; - for (i=0, n=n0; n; i++,n=n->cdr) { - cxt->syms[i] = sym(n->car); - } -} - -void mrb_codedump_all(mrb_state*, struct RProc*); -void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); - -MRB_API void -mrb_parser_parse(parser_state *p, mrbc_context *c) -{ - struct mrb_jmpbuf buf; - p->jmp = &buf; - - MRB_TRY(p->jmp) { - - p->cmd_start = TRUE; - p->in_def = p->in_single = 0; - p->nerr = p->nwarn = 0; - p->lex_strterm = NULL; - - parser_init_cxt(p, c); - yyparse(p); - if (!p->tree) { - p->tree = new_nil(p); - } - parser_update_cxt(p, c); - if (c && c->dump_result) { - mrb_parser_dump(p->mrb, p->tree, 0); - } - - } - MRB_CATCH(p->jmp) { - yyerror(p, "memory allocation error"); - p->nerr++; - p->tree = 0; - return; - } - MRB_END_EXC(p->jmp); -} - -MRB_API parser_state* -mrb_parser_new(mrb_state *mrb) -{ - mrb_pool *pool; - parser_state *p; - static const parser_state parser_state_zero = { 0 }; - - pool = mrb_pool_open(mrb); - if (!pool) return NULL; - p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state)); - if (!p) return NULL; - - *p = parser_state_zero; - p->mrb = mrb; - p->pool = pool; - - p->s = p->send = NULL; -#ifdef ENABLE_STDIO - p->f = NULL; -#endif - - p->cmd_start = TRUE; - p->in_def = p->in_single = 0; - - p->capture_errors = FALSE; - p->lineno = 1; - p->column = 0; -#if defined(PARSER_TEST) || defined(PARSER_DEBUG) - yydebug = 1; -#endif - - p->lex_strterm = NULL; - p->all_heredocs = p->parsing_heredoc = NULL; - p->lex_strterm_before_heredoc = NULL; - - p->current_filename_index = -1; - p->filename_table = NULL; - p->filename_table_length = 0; - - return p; -} - -MRB_API void -mrb_parser_free(parser_state *p) { - mrb_pool_close(p->pool); -} - -MRB_API mrbc_context* -mrbc_context_new(mrb_state *mrb) -{ - return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); -} - -MRB_API void -mrbc_context_free(mrb_state *mrb, mrbc_context *cxt) -{ - mrb_free(mrb, cxt->syms); - mrb_free(mrb, cxt); -} - -MRB_API const char* -mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) -{ - if (s) { - int len = strlen(s); - char *p = (char *)mrb_alloca(mrb, len + 1); - - memcpy(p, s, len + 1); - c->filename = p; - } - return c->filename; -} - -MRB_API void -mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data) -{ - c->partial_hook = func; - c->partial_data = data; -} - -MRB_API void -mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) -{ - mrb_sym sym; - size_t i; - mrb_sym* new_table; - - sym = mrb_intern_cstr(p->mrb, f); - p->filename = mrb_sym2name_len(p->mrb, sym, NULL); - p->lineno = (p->filename_table_length > 0)? 0 : 1; - - for (i = 0; i < p->filename_table_length; ++i) { - if (p->filename_table[i] == sym) { - p->current_filename_index = i; - return; - } - } - - p->current_filename_index = p->filename_table_length++; - - new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); - if (p->filename_table) { - memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length); - } - p->filename_table = new_table; - p->filename_table[p->filename_table_length - 1] = sym; -} - -MRB_API char const* -mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { - if (idx >= p->filename_table_length) { return NULL; } - else { - return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); - } -} - -#ifdef ENABLE_STDIO -MRB_API parser_state* -mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) -{ - parser_state *p; - - p = mrb_parser_new(mrb); - if (!p) return NULL; - p->s = p->send = NULL; - p->f = f; - - mrb_parser_parse(p, c); - return p; -} -#endif - -MRB_API parser_state* -mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c) -{ - parser_state *p; - - p = mrb_parser_new(mrb); - if (!p) return NULL; - p->s = s; - p->send = s + len; - - mrb_parser_parse(p, c); - return p; -} - -MRB_API parser_state* -mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c) -{ - return mrb_parse_nstring(mrb, s, strlen(s), c); -} - -static mrb_value -load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) -{ - struct RClass *target = mrb->object_class; - struct RProc *proc; - mrb_value v; - unsigned int keep = 0; - - if (!p) { - return mrb_undef_value(); - } - if (!p->tree || p->nerr) { - if (p->capture_errors) { - char buf[256]; - int n; - - n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); - mrb_parser_free(p); - return mrb_undef_value(); - } - else { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error")); - mrb_parser_free(p); - return mrb_undef_value(); - } - } - proc = mrb_generate_code(mrb, p); - mrb_parser_free(p); - if (proc == NULL) { - mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error")); - return mrb_undef_value(); - } - if (c) { - if (c->dump_result) mrb_codedump_all(mrb, proc); - if (c->no_exec) return mrb_obj_value(proc); - if (c->target_class) { - target = c->target_class; - } - if (c->keep_lv) { - keep = c->slen + 1; - } - else { - c->keep_lv = TRUE; - } - } - proc->target_class = target; - if (mrb->c->ci) { - mrb->c->ci->target_class = target; - } - v = mrb_toplevel_run_keep(mrb, proc, keep); - if (mrb->exc) return mrb_nil_value(); - return v; -} - -#ifdef ENABLE_STDIO -MRB_API mrb_value -mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c) -{ - return load_exec(mrb, mrb_parse_file(mrb, f, c), c); -} - -MRB_API mrb_value -mrb_load_file(mrb_state *mrb, FILE *f) -{ - return mrb_load_file_cxt(mrb, f, NULL); -} -#endif - -MRB_API mrb_value -mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c) -{ - return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c); -} - -MRB_API mrb_value -mrb_load_nstring(mrb_state *mrb, const char *s, int len) -{ - return mrb_load_nstring_cxt(mrb, s, len, NULL); -} - -MRB_API mrb_value -mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c) -{ - return mrb_load_nstring_cxt(mrb, s, strlen(s), c); -} - -MRB_API mrb_value -mrb_load_string(mrb_state *mrb, const char *s) -{ - return mrb_load_string_cxt(mrb, s, NULL); -} - -#ifdef ENABLE_STDIO - -static void -dump_prefix(node *tree, int offset) -{ - printf("%05d ", tree->lineno); - while (offset--) { - putc(' ', stdout); - putc(' ', stdout); - } -} - -static void -dump_recur(mrb_state *mrb, node *tree, int offset) -{ - while (tree) { - mrb_parser_dump(mrb, tree->car, offset); - tree = tree->cdr; - } -} - -#endif - -void -mrb_parser_dump(mrb_state *mrb, node *tree, int offset) -{ -#ifdef ENABLE_STDIO - int nodetype; - - if (!tree) return; - again: - dump_prefix(tree, offset); - nodetype = (int)(intptr_t)tree->car; - tree = tree->cdr; - switch (nodetype) { - case NODE_BEGIN: - printf("NODE_BEGIN:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_RESCUE: - printf("NODE_RESCUE:\n"); - if (tree->car) { - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - } - tree = tree->cdr; - if (tree->car) { - node *n2 = tree->car; - - dump_prefix(n2, offset+1); - printf("rescue:\n"); - while (n2) { - node *n3 = n2->car; - if (n3->car) { - dump_prefix(n2, offset+2); - printf("handle classes:\n"); - dump_recur(mrb, n3->car, offset+3); - } - if (n3->cdr->car) { - dump_prefix(n3, offset+2); - printf("exc_var:\n"); - mrb_parser_dump(mrb, n3->cdr->car, offset+3); - } - if (n3->cdr->cdr->car) { - dump_prefix(n3, offset+2); - printf("rescue body:\n"); - mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); - } - n2 = n2->cdr; - } - } - tree = tree->cdr; - if (tree->car) { - dump_prefix(tree, offset+1); - printf("else:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - } - break; - - case NODE_ENSURE: - printf("NODE_ENSURE:\n"); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("ensure:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); - break; - - case NODE_LAMBDA: - printf("NODE_BLOCK:\n"); - goto block; - - case NODE_BLOCK: - block: - printf("NODE_BLOCK:\n"); - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - break; - - case NODE_IF: - printf("NODE_IF:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("then:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - if (tree->cdr->cdr->car) { - dump_prefix(tree, offset+1); - printf("else:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); - } - break; - - case NODE_AND: - printf("NODE_AND:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_OR: - printf("NODE_OR:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_CASE: - printf("NODE_CASE:\n"); - if (tree->car) { - mrb_parser_dump(mrb, tree->car, offset+1); - } - tree = tree->cdr; - while (tree) { - dump_prefix(tree, offset+1); - printf("case:\n"); - dump_recur(mrb, tree->car->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->car->cdr, offset+2); - tree = tree->cdr; - } - break; - - case NODE_WHILE: - printf("NODE_WHILE:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_UNTIL: - printf("NODE_UNTIL:\n"); - dump_prefix(tree, offset+1); - printf("cond:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_FOR: - printf("NODE_FOR:\n"); - dump_prefix(tree, offset+1); - printf("var:\n"); - { - node *n2 = tree->car; - - if (n2->car) { - dump_prefix(n2, offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("rest:\n"); - mrb_parser_dump(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } - } - } - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("in:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("do:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - break; - - case NODE_SCOPE: - printf("NODE_SCOPE:\n"); - { - node *n2 = tree->car; - mrb_bool first_lval = TRUE; - - if (n2 && (n2->car || n2->cdr)) { - dump_prefix(n2, offset+1); - printf("local variables:\n"); - dump_prefix(n2, offset+2); - while (n2) { - if (n2->car) { - if (!first_lval) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - first_lval = FALSE; - } - n2 = n2->cdr; - } - printf("\n"); - } - } - tree = tree->cdr; - offset++; - goto again; - - case NODE_FCALL: - case NODE_CALL: - printf("NODE_CALL:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("method='%s' (%d)\n", - mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); - tree = tree->cdr->cdr->car; - if (tree) { - dump_prefix(tree, offset+1); - printf("args:\n"); - dump_recur(mrb, tree->car, offset+2); - if (tree->cdr) { - dump_prefix(tree, offset+1); - printf("block:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - } - } - break; - - case NODE_DOT2: - printf("NODE_DOT2:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_DOT3: - printf("NODE_DOT3:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - mrb_parser_dump(mrb, tree->cdr, offset+1); - break; - - case NODE_COLON2: - printf("NODE_COLON2:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); - break; - - case NODE_COLON3: - printf("NODE_COLON3:\n"); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_ARRAY: - printf("NODE_ARRAY:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_HASH: - printf("NODE_HASH:\n"); - while (tree) { - dump_prefix(tree, offset+1); - printf("key:\n"); - mrb_parser_dump(mrb, tree->car->car, offset+2); - dump_prefix(tree, offset+1); - printf("value:\n"); - mrb_parser_dump(mrb, tree->car->cdr, offset+2); - tree = tree->cdr; - } - break; - - case NODE_SPLAT: - printf("NODE_SPLAT:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_ASGN: - printf("NODE_ASGN:\n"); - dump_prefix(tree, offset+1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - dump_prefix(tree, offset+1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_MASGN: - printf("NODE_MASGN:\n"); - dump_prefix(tree, offset+1); - printf("mlhs:\n"); - { - node *n2 = tree->car; - - if (n2->car) { - dump_prefix(tree, offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("rest:\n"); - if (n2->car == (node*)-1) { - dump_prefix(n2, offset+2); - printf("(empty)\n"); - } - else { - mrb_parser_dump(mrb, n2->car, offset+3); - } - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(n2, offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } - } - } - dump_prefix(tree, offset+1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - break; - - case NODE_OP_ASGN: - printf("NODE_OP_ASGN:\n"); - dump_prefix(tree, offset+1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset+2); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); - tree = tree->cdr; - mrb_parser_dump(mrb, tree->car, offset+1); - break; - - case NODE_SUPER: - printf("NODE_SUPER:\n"); - if (tree) { - dump_prefix(tree, offset+1); - printf("args:\n"); - dump_recur(mrb, tree->car, offset+2); - if (tree->cdr) { - dump_prefix(tree, offset+1); - printf("block:\n"); - mrb_parser_dump(mrb, tree->cdr, offset+2); - } - } - break; - - case NODE_ZSUPER: - printf("NODE_ZSUPER\n"); - break; - - case NODE_RETURN: - printf("NODE_RETURN:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_YIELD: - printf("NODE_YIELD:\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_BREAK: - printf("NODE_BREAK:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_NEXT: - printf("NODE_NEXT:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_REDO: - printf("NODE_REDO\n"); - break; - - case NODE_RETRY: - printf("NODE_RETRY\n"); - break; - - case NODE_LVAR: - printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_GVAR: - printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_IVAR: - printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_CVAR: - printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_CONST: - printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_MATCH: - printf("NODE_MATCH:\n"); - dump_prefix(tree, offset + 1); - printf("lhs:\n"); - mrb_parser_dump(mrb, tree->car, offset + 2); - dump_prefix(tree, offset + 1); - printf("rhs:\n"); - mrb_parser_dump(mrb, tree->cdr, offset + 2); - break; - - case NODE_BACK_REF: - printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); - break; - - case NODE_NTH_REF: - printf("NODE_NTH_REF: $%d\n", (int)(intptr_t)tree); - break; - - case NODE_ARG: - printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_BLOCK_ARG: - printf("NODE_BLOCK_ARG:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_INT: - printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); - break; - - case NODE_FLOAT: - printf("NODE_FLOAT %s\n", (char*)tree); - break; - - case NODE_NEGATE: - printf("NODE_NEGATE\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_STR: - printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); - break; - - case NODE_DSTR: - printf("NODE_DSTR\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_XSTR: - printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); - break; - - case NODE_DXSTR: - printf("NODE_DXSTR\n"); - dump_recur(mrb, tree, offset+1); - break; - - case NODE_REGX: - printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr); - break; - - case NODE_DREGX: - printf("NODE_DREGX\n"); - dump_recur(mrb, tree->car, offset+1); - dump_prefix(tree, offset); - printf("tail: %s\n", (char*)tree->cdr->cdr->car); - dump_prefix(tree, offset); - printf("opt: %s\n", (char*)tree->cdr->cdr->cdr); - break; - - case NODE_SYM: - printf("NODE_SYM :%s\n", mrb_sym2name(mrb, sym(tree))); - break; - - case NODE_SELF: - printf("NODE_SELF\n"); - break; - - case NODE_NIL: - printf("NODE_NIL\n"); - break; - - case NODE_TRUE: - printf("NODE_TRUE\n"); - break; - - case NODE_FALSE: - printf("NODE_FALSE\n"); - break; - - case NODE_ALIAS: - printf("NODE_ALIAS %s %s:\n", - mrb_sym2name(mrb, sym(tree->car)), - mrb_sym2name(mrb, sym(tree->cdr))); - break; - - case NODE_UNDEF: - printf("NODE_UNDEF"); - { - node *t = tree; - while (t) { - printf(" %s", mrb_sym2name(mrb, sym(t->car))); - t = t->cdr; - } - } - printf(":\n"); - break; - - case NODE_CLASS: - printf("NODE_CLASS:\n"); - if (tree->car->car == (node*)0) { - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else if (tree->car->car == (node*)1) { - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else { - mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - if (tree->cdr->car) { - dump_prefix(tree, offset+1); - printf("super:\n"); - mrb_parser_dump(mrb, tree->cdr->car, offset+2); - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); - break; - - case NODE_MODULE: - printf("NODE_MODULE:\n"); - if (tree->car->car == (node*)0) { - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else if (tree->car->car == (node*)1) { - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - else { - mrb_parser_dump(mrb, tree->car->car, offset+1); - dump_prefix(tree, offset+1); - printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); - } - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); - break; - - case NODE_SCLASS: - printf("NODE_SCLASS:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - dump_prefix(tree, offset+1); - printf("body:\n"); - mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); - break; - - case NODE_DEF: - printf("NODE_DEF:\n"); - dump_prefix(tree, offset+1); - printf("%s\n", mrb_sym2name(mrb, sym(tree->car))); - tree = tree->cdr; - { - node *n2 = tree->car; - mrb_bool first_lval = TRUE; - - if (n2 && (n2->car || n2->cdr)) { - dump_prefix(n2, offset+1); - printf("local variables:\n"); - dump_prefix(n2, offset+2); - while (n2) { - if (n2->car) { - if (!first_lval) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - first_lval = FALSE; - } - n2 = n2->cdr; - } - printf("\n"); - } - } - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } - } - mrb_parser_dump(mrb, tree->cdr->car, offset+1); - break; - - case NODE_SDEF: - printf("NODE_SDEF:\n"); - mrb_parser_dump(mrb, tree->car, offset+1); - tree = tree->cdr; - dump_prefix(tree, offset+1); - printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); - tree = tree->cdr->cdr; - if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } - } - tree = tree->cdr; - mrb_parser_dump(mrb, tree->car, offset+1); - break; - - case NODE_POSTEXE: - printf("NODE_POSTEXE:\n"); - mrb_parser_dump(mrb, tree, offset+1); - break; - - case NODE_HEREDOC: - printf("NODE_HEREDOC:\n"); - mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); - break; - - default: - printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); - break; - } -#endif -} diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 66608286d..50bed0fbe 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -80,7 +80,7 @@ module MRuby @git = Command::Git.new(self) @mrbc = Command::Mrbc.new(self) - @bins = %w(mrbc) + @bins = [] @gems, @libmruby = MRuby::Gem::List.new, [] @build_mrbtest_lib_only = false @cxx_abi_enabled = false @@ -92,6 +92,8 @@ module MRuby MRuby::Build.current = MRuby.targets[@name] MRuby.targets[@name].instance_eval(&block) + + build_mrbc_exec if name == 'host' end def enable_debug @@ -119,6 +121,33 @@ module MRuby @cxx_abi_enabled = true end + def compile_as_cxx src, cxx_src, obj = nil, includes = [] + src = File.absolute_path src + cxx_src = File.absolute_path cxx_src + obj = objfile(cxx_src) if obj.nil? + + file cxx_src => [src, __FILE__] do |t| + File.open(t.name, 'w') do |f| + f.write < cxx_src do |t| + cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes + end + + obj + end + def enable_bintest @enable_bintest = true end @@ -142,8 +171,16 @@ module MRuby MRUBY_ROOT end + def build_mrbc_exec + gem :core => 'mruby-bin-mrbc' + end + def mrbcfile - MRuby.targets[@name].exefile("#{MRuby.targets[@name].build_dir}/bin/mrbc") + return @mrbcfile if @mrbcfile + + mrbc_build = MRuby.targets['host'] + gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' } + @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc") end def compilers diff --git a/tools/mrbc/mrbc.c b/tools/mrbc/mrbc.c deleted file mode 100644 index f27f87a5d..000000000 --- a/tools/mrbc/mrbc.c +++ /dev/null @@ -1,337 +0,0 @@ -#include -#include -#include -#include "mruby.h" -#include "mruby/compile.h" -#include "mruby/dump.h" -#include "mruby/proc.h" - -#define RITEBIN_EXT ".mrb" -#define C_EXT ".c" - -struct mrbc_args { - int argc; - char **argv; - int idx; - const char *prog; - const char *outfile; - const char *initname; - mrb_bool check_syntax : 1; - mrb_bool verbose : 1; - unsigned int flags : 4; -}; - -static void -usage(const char *name) -{ - static const char *const usage_msg[] = { - "switches:", - "-c check syntax only", - "-o place the output into ", - "-v print version number, then turn on verbose mode", - "-g produce debugging information", - "-B binary output in C language format", - "-e generate little endian iseq data", - "-E generate big endian iseq data", - "--verbose run at verbose mode", - "--version print the version", - "--copyright print the copyright", - NULL - }; - const char *const *p = usage_msg; - - printf("Usage: %s [switches] programfile\n", name); - while (*p) - printf(" %s\n", *p++); -} - -static char * -get_outfilename(mrb_state *mrb, char *infile, const char *ext) -{ - size_t infilelen; - size_t extlen; - char *outfile; - char *p; - - infilelen = strlen(infile); - extlen = strlen(ext); - outfile = (char*)mrb_malloc(mrb, infilelen + extlen + 1); - memcpy(outfile, infile, infilelen + 1); - if (*ext) { - if ((p = strrchr(outfile, '.')) == NULL) - p = outfile + infilelen; - memcpy(p, ext, extlen + 1); - } - - return outfile; -} - -static int -parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) -{ - char *outfile = NULL; - static const struct mrbc_args args_zero = { 0 }; - int i; - - *args = args_zero; - args->argc = argc; - args->argv = argv; - args->prog = argv[0]; - - for (i=1; ioutfile) { - fprintf(stderr, "%s: an output file is already specified. (%s)\n", - args->prog, outfile); - return -1; - } - if (argv[i][2] == '\0' && argv[i+1]) { - i++; - args->outfile = get_outfilename(mrb, argv[i], ""); - } - else { - args->outfile = get_outfilename(mrb, argv[i] + 2, ""); - } - break; - case 'B': - if (argv[i][2] == '\0' && argv[i+1]) { - i++; - args->initname = argv[i]; - } - else { - args->initname = argv[i]+2; - } - if (*args->initname == '\0') { - fprintf(stderr, "%s: function name is not specified.\n", args->prog); - return -1; - } - break; - case 'c': - args->check_syntax = TRUE; - break; - case 'v': - if (!args->verbose) mrb_show_version(mrb); - args->verbose = TRUE; - break; - case 'g': - args->flags |= DUMP_DEBUG_INFO; - break; - case 'E': - args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); - break; - case 'e': - args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); - break; - case 'h': - return -1; - case '-': - if (argv[i][1] == '\n') { - return i; - } - if (strcmp(argv[i] + 2, "version") == 0) { - mrb_show_version(mrb); - exit(EXIT_SUCCESS); - } - else if (strcmp(argv[i] + 2, "verbose") == 0) { - args->verbose = TRUE; - break; - } - else if (strcmp(argv[i] + 2, "copyright") == 0) { - mrb_show_copyright(mrb); - exit(EXIT_SUCCESS); - } - return -1; - default: - return i; - } - } - else { - break; - } - } - if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) { - fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n", - args->prog, bigendian_p() ? "big" : "little"); - } - return i; -} - -static void -cleanup(mrb_state *mrb, struct mrbc_args *args) -{ - if (args->outfile) - mrb_free(mrb, (void*)args->outfile); - mrb_close(mrb); -} - -static int -partial_hook(struct mrb_parser_state *p) -{ - mrbc_context *c = p->cxt; - struct mrbc_args *args = (struct mrbc_args *)c->partial_data; - const char *fn; - - if (p->f) fclose(p->f); - if (args->idx >= args->argc) { - p->f = NULL; - return -1; - } - fn = args->argv[args->idx++]; - p->f = fopen(fn, "r"); - if (p->f == NULL) { - fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn); - return -1; - } - mrb_parser_set_filename(p, fn); - return 0; -} - -static mrb_value -load_file(mrb_state *mrb, struct mrbc_args *args) -{ - mrbc_context *c; - mrb_value result; - char *input = args->argv[args->idx]; - FILE *infile; - mrb_bool need_close = FALSE; - - c = mrbc_context_new(mrb); - if (args->verbose) - c->dump_result = TRUE; - c->no_exec = TRUE; - if (input[0] == '-' && input[1] == '\0') { - infile = stdin; - } - else { - need_close = TRUE; - if ((infile = fopen(input, "r")) == NULL) { - fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input); - return mrb_nil_value(); - } - } - mrbc_filename(mrb, c, input); - args->idx++; - if (args->idx < args->argc) { - need_close = FALSE; - mrbc_partial_hook(mrb, c, partial_hook, (void*)args); - } - - result = mrb_load_file_cxt(mrb, infile, c); - if (need_close) fclose(infile); - mrbc_context_free(mrb, c); - if (mrb_undef_p(result)) { - return mrb_nil_value(); - } - return result; -} - -static int -dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, struct mrbc_args *args) -{ - int n = MRB_DUMP_OK; - mrb_irep *irep = proc->body.irep; - - if (args->initname) { - n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); - if (n == MRB_DUMP_INVALID_ARGUMENT) { - fprintf(stderr, "%s: invalid C language symbol name\n", args->initname); - } - } - else { - n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp); - } - if (n != MRB_DUMP_OK) { - fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n); - } - return n; -} - -int -main(int argc, char **argv) -{ - mrb_state *mrb = mrb_open(); - int n, result; - struct mrbc_args args; - FILE *wfp; - mrb_value load; - - if (mrb == NULL) { - fputs("Invalid mrb_state, exiting mrbc\n", stderr); - return EXIT_FAILURE; - } - - n = parse_args(mrb, argc, argv, &args); - if (n < 0) { - cleanup(mrb, &args); - usage(argv[0]); - return EXIT_FAILURE; - } - if (n == argc) { - fprintf(stderr, "%s: no program file given\n", args.prog); - return EXIT_FAILURE; - } - if (args.outfile == NULL && !args.check_syntax) { - if (n + 1 == argc) { - args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT); - } - else { - fprintf(stderr, "%s: output file should be specified to compile multiple files\n", args.prog); - return EXIT_FAILURE; - } - } - - args.idx = n; - load = load_file(mrb, &args); - if (mrb_nil_p(load)) { - cleanup(mrb, &args); - return EXIT_FAILURE; - } - if (args.check_syntax) { - printf("%s:%s:Syntax OK\n", args.prog, argv[n]); - } - - if (args.check_syntax) { - cleanup(mrb, &args); - return EXIT_SUCCESS; - } - - if (args.outfile) { - if (strcmp("-", args.outfile) == 0) { - wfp = stdout; - } - else if ((wfp = fopen(args.outfile, "wb")) == NULL) { - fprintf(stderr, "%s: cannot open output file:(%s)\n", args.prog, args.outfile); - return EXIT_FAILURE; - } - } - else { - fprintf(stderr, "Output file is required\n"); - return EXIT_FAILURE; - } - result = dump_file(mrb, wfp, args.outfile, mrb_proc_ptr(load), &args); - fclose(wfp); - cleanup(mrb, &args); - if (result != MRB_DUMP_OK) { - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -void -mrb_init_mrblib(mrb_state *mrb) -{ -} - -#ifndef DISABLE_GEMS -void -mrb_init_mrbgems(mrb_state *mrb) -{ -} - -void -mrb_final_mrbgems(mrb_state *mrb) -{ -} -#endif diff --git a/tools/mrbc/mrbc.rake b/tools/mrbc/mrbc.rake deleted file mode 100644 index 1a0309a0d..000000000 --- a/tools/mrbc/mrbc.rake +++ /dev/null @@ -1,14 +0,0 @@ -MRuby.each_target do - current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) - relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) - current_build_dir = "#{build_dir}/#{relative_from_root}" - - if bins.find { |s| s.to_s == 'mrbc' } - exec = exefile("#{build_dir}/bin/mrbc") - objs = Dir.glob("#{current_dir}/*.c").map { |f| objfile(f.pathmap("#{current_build_dir}/%n")) }.flatten - - file exec => objs + [libfile("#{build_dir}/lib/libmruby_core")] do |t| - linker.run t.name, t.prerequisites - end - end -end diff --git a/travis_config.rb b/travis_config.rb index fadafd8c1..2b4059cf1 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -8,6 +8,8 @@ MRuby::Build.new('debug') do |conf| conf.compilers.each do |c| c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA) end + + build_mrbc_exec end MRuby::Build.new do |conf| @@ -33,4 +35,6 @@ MRuby::Build.new('cxx_abi') do |conf| conf.enable_bintest enable_cxx_abi + + build_mrbc_exec end -- cgit v1.2.3 From 2f635f56cb701293c59cc2e4f41b653cae2cb3af Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Jun 2015 21:57:53 +0900 Subject: update lex.def using gperf 3.0.4 --- mrbgems/mruby-compiler/core/lex.def | 92 ++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/mrbgems/mruby-compiler/core/lex.def b/mrbgems/mruby-compiler/core/lex.def index ea456a843..58e302965 100644 --- a/mrbgems/mruby-compiler/core/lex.def +++ b/mrbgems/mruby-compiler/core/lex.def @@ -1,5 +1,5 @@ -/* ANSI-C code produced by gperf version 3.0.3 */ -/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */ +/* ANSI-C code produced by gperf version 3.0.4 */ +/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ @@ -28,13 +28,13 @@ #error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif -#line 1 "src/keywords" +#line 1 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; const struct kwtable *mrb_reserved_word(const char *, unsigned int); static const struct kwtable *reserved_word(const char *, unsigned int); #define mrb_reserved_word(str, len) reserved_word(str, len) -#line 8 "src/keywords" +#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable; #define TOTAL_KEYWORDS 40 @@ -100,7 +100,7 @@ hash (register const char *str, register unsigned int len) #ifdef __GNUC__ __inline -#ifdef __GNUC_STDC_INLINE__ +#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ __attribute__ ((__gnu_inline__)) #endif #endif @@ -110,87 +110,87 @@ mrb_reserved_word (register const char *str, register unsigned int len) static const struct kwtable wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 18 "src/keywords" +#line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"break", {keyword_break, keyword_break}, EXPR_MID}, -#line 23 "src/keywords" +#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"else", {keyword_else, keyword_else}, EXPR_BEG}, -#line 33 "src/keywords" +#line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"nil", {keyword_nil, keyword_nil}, EXPR_END}, -#line 26 "src/keywords" +#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, -#line 25 "src/keywords" +#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"end", {keyword_end, keyword_end}, EXPR_END}, -#line 42 "src/keywords" +#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"then", {keyword_then, keyword_then}, EXPR_BEG}, -#line 34 "src/keywords" +#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"not", {keyword_not, keyword_not}, EXPR_ARG}, -#line 27 "src/keywords" +#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"false", {keyword_false, keyword_false}, EXPR_END}, -#line 40 "src/keywords" +#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"self", {keyword_self, keyword_self}, EXPR_END}, -#line 24 "src/keywords" +#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, -#line 37 "src/keywords" +#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, -#line 43 "src/keywords" +#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"true", {keyword_true, keyword_true}, EXPR_END}, -#line 46 "src/keywords" +#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"until", {keyword_until, modifier_until}, EXPR_VALUE}, -#line 45 "src/keywords" +#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, -#line 39 "src/keywords" +#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"return", {keyword_return, keyword_return}, EXPR_MID}, -#line 21 "src/keywords" +#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"def", {keyword_def, keyword_def}, EXPR_FNAME}, -#line 16 "src/keywords" +#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"and", {keyword_and, keyword_and}, EXPR_VALUE}, -#line 22 "src/keywords" +#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"do", {keyword_do, keyword_do}, EXPR_BEG}, -#line 49 "src/keywords" +#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, -#line 28 "src/keywords" +#line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"for", {keyword_for, keyword_for}, EXPR_VALUE}, -#line 44 "src/keywords" +#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, -#line 35 "src/keywords" +#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"or", {keyword_or, keyword_or}, EXPR_VALUE}, -#line 30 "src/keywords" +#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"in", {keyword_in, keyword_in}, EXPR_VALUE}, -#line 47 "src/keywords" +#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"when", {keyword_when, keyword_when}, EXPR_VALUE}, -#line 38 "src/keywords" +#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"retry", {keyword_retry, keyword_retry}, EXPR_END}, -#line 29 "src/keywords" +#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"if", {keyword_if, modifier_if}, EXPR_VALUE}, -#line 19 "src/keywords" +#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"case", {keyword_case, keyword_case}, EXPR_VALUE}, -#line 36 "src/keywords" +#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"redo", {keyword_redo, keyword_redo}, EXPR_END}, -#line 32 "src/keywords" +#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"next", {keyword_next, keyword_next}, EXPR_MID}, -#line 41 "src/keywords" +#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"super", {keyword_super, keyword_super}, EXPR_ARG}, -#line 31 "src/keywords" +#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"module", {keyword_module, keyword_module}, EXPR_VALUE}, -#line 17 "src/keywords" +#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, -#line 12 "src/keywords" +#line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, -#line 11 "src/keywords" +#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, -#line 10 "src/keywords" +#line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, -#line 14 "src/keywords" +#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"END", {keyword_END, keyword_END}, EXPR_END}, -#line 15 "src/keywords" +#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, -#line 13 "src/keywords" +#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, {""}, -#line 20 "src/keywords" +#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"class", {keyword_class, keyword_class}, EXPR_CLASS}, {""}, {""}, -#line 48 "src/keywords" +#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"while", {keyword_while, modifier_while}, EXPR_VALUE} }; @@ -208,5 +208,5 @@ mrb_reserved_word (register const char *str, register unsigned int len) } return 0; } -#line 50 "src/keywords" +#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" -- cgit v1.2.3 From b721d449e6c9ad905e62a7632037ceb9900f812f Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Jun 2015 07:57:27 +0200 Subject: push only after OP_GETCONST in VAL mode; ref #2769 --- mrbgems/mruby-compiler/core/codegen.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 16233347c..d2eeef203 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1942,7 +1942,9 @@ codegen(codegen_scope *s, node *tree, int val) int sym = new_sym(s, sym(tree)); genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - push(); + if (val) { + push(); + } } break; -- cgit v1.2.3 From 599d141cc8fa7b04398d564b09893f6754906f3e Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Jun 2015 08:34:36 +0200 Subject: directly call ary_new_capa() --- src/array.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/array.c b/src/array.c index 1ca7dd2a4..f2584114d 100644 --- a/src/array.c +++ b/src/array.c @@ -88,15 +88,12 @@ array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals) { - mrb_value ary; - struct RArray *a; + struct RArray *a = ary_new_capa(mrb, size); - ary = mrb_ary_new_capa(mrb, size); - a = mrb_ary_ptr(ary); array_copy(a->ptr, vals, size); a->len = size; - return ary; + return mrb_obj_value(a); } MRB_API mrb_value @@ -293,7 +290,6 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int blen; @@ -301,13 +297,12 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) if (ARY_MAX_SIZE - blen < a1->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } - ary = mrb_ary_new_capa(mrb, a1->len + blen); - a2 = mrb_ary_ptr(ary); + a2 = ary_new_capa(mrb, a1->len + blen); array_copy(a2->ptr, a1->ptr, a1->len); array_copy(a2->ptr + a1->len, ptr, blen); a2->len = a1->len + blen; - return ary; + return mrb_obj_value(a2); } static void @@ -345,7 +340,6 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) { struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2; - mrb_value ary; mrb_value *ptr; mrb_int times; @@ -357,8 +351,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) if (ARY_MAX_SIZE / times < a1->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } - ary = mrb_ary_new_capa(mrb, a1->len * times); - a2 = mrb_ary_ptr(ary); + a2 = ary_new_capa(mrb, a1->len * times); ptr = a2->ptr; while (times--) { array_copy(ptr, a1->ptr, a1->len); @@ -366,7 +359,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) a2->len += a1->len; } - return ary; + return mrb_obj_value(a2); } static mrb_value @@ -393,11 +386,8 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self) static mrb_value mrb_ary_reverse(mrb_state *mrb, mrb_value self) { - struct RArray *a = mrb_ary_ptr(self), *b; - mrb_value ary; + struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len); - ary = mrb_ary_new_capa(mrb, a->len); - b = mrb_ary_ptr(ary); if (a->len > 0) { mrb_value *p1, *p2, *e; @@ -409,7 +399,7 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self) } b->len = a->len; } - return ary; + return mrb_obj_value(b); } MRB_API void -- cgit v1.2.3 From ef0fc90cd007d613be6c268cc6adbecc8d7a0a8f Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Jun 2015 08:56:41 +0200 Subject: remove unnecessary mrb_immediate_p() `!mrb_array_p(ary2)` and `mrb_type(obj) != MRB_TT_DATA` are sufficient. --- src/array.c | 2 -- src/etc.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/array.c b/src/array.c index 1ca7dd2a4..c97e7a53b 100644 --- a/src/array.c +++ b/src/array.c @@ -1052,7 +1052,6 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); - if (mrb_immediate_p(ary2)) return mrb_false_value(); if (!mrb_array_p(ary2)) { return mrb_false_value(); } @@ -1068,7 +1067,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) mrb_get_args(mrb, "o", &ary2); if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); - if (mrb_immediate_p(ary2)) return mrb_nil_value(); if (!mrb_array_p(ary2)) { return mrb_nil_value(); } diff --git a/src/etc.c b/src/etc.c index 635052b67..a8a21e740 100644 --- a/src/etc.c +++ b/src/etc.c @@ -26,7 +26,7 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_immediate_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { mrb_check_type(mrb, obj, MRB_TT_DATA); } if (DATA_TYPE(obj) != type) { @@ -48,7 +48,7 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API void* mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) { - if (mrb_immediate_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) { + if (mrb_type(obj) != MRB_TT_DATA) { return NULL; } if (DATA_TYPE(obj) != type) { -- cgit v1.2.3 From cd38bcf074cbac24be458b4f14b111335f5a87db Mon Sep 17 00:00:00 2001 From: Mav7 Date: Thu, 4 Jun 2015 23:34:03 -0400 Subject: Adding an array readme markdown. --- doc/api/array.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/array.h.md diff --git a/doc/api/array.h.md b/doc/api/array.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From b735c0d9dfece2b1cc53947a4057c535bbcb773f Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 4 Jun 2015 23:37:41 -0400 Subject: Update README.md --- doc/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 78dbc087d..131e50515 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -25,6 +25,6 @@ Header name|Features [mruby/range.h](./mruby.range.h.md)|`Range` class. [mruby/re.h](./mruby.re.h.md)|`Regexp` class. [mruby/string.h](./mruby.string.h.md)|`String` class. -[mruby/value.h](./value.h.md)|`mrb_value` functions and macros. +[mruby/value.h](./mruby.value.h.md)|`mrb_value` functions and macros. [mruby/variable.h](./mruby.variable.h.md)|Functions to access to mruby variables. [mruby/version.h](./mruby.version.h.md)|Macros of mruby version. -- cgit v1.2.3 From 5d63350a3b7074694f0a7a361900814b513e01cf Mon Sep 17 00:00:00 2001 From: Mav7 Date: Thu, 4 Jun 2015 23:46:32 -0400 Subject: testing something. --- doc/api/array.h.md | 0 doc/api/mruby/array.h.md | 0 doc/api/mruby/value.h.md | 233 +++++++++++++++++++++++++++++++++++++++++++++++ doc/api/value.h.md | 233 ----------------------------------------------- 4 files changed, 233 insertions(+), 233 deletions(-) delete mode 100644 doc/api/array.h.md create mode 100644 doc/api/mruby/array.h.md create mode 100644 doc/api/mruby/value.h.md delete mode 100644 doc/api/value.h.md diff --git a/doc/api/array.h.md b/doc/api/array.h.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md new file mode 100644 index 000000000..e69de29bb diff --git a/doc/api/mruby/value.h.md b/doc/api/mruby/value.h.md new file mode 100644 index 000000000..dd1c4b238 --- /dev/null +++ b/doc/api/mruby/value.h.md @@ -0,0 +1,233 @@ +### mrb_float_value +```C +static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) +``` + +Returns a float in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively +double i = 0.09 could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" +#include "mruby/string.h" + +int +main(void) +{ + mrb_float f = 0.09;// or double i = 0.09; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + +### mrb_fixnum_value + +```C +static inline mrb_value mrb_fixnum_value(mrb_int i) +``` + +Returns a fixnum in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 +could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_int i = 99; // or int i = 99; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_nil_value + +```C +static inline mrb_value mrb_nil_value(void) +``` + +Returns nil in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + +### mrb_false_value + +```C +static inline mrb_value mrb_false_value(void) +``` + +Returns false in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_true_value + +```C +static inline mrb_value mrb_true_value(void) +``` + +Returns true in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` diff --git a/doc/api/value.h.md b/doc/api/value.h.md deleted file mode 100644 index dd1c4b238..000000000 --- a/doc/api/value.h.md +++ /dev/null @@ -1,233 +0,0 @@ -### mrb_float_value -```C -static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) -``` - -Returns a float in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively -double i = 0.09 could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" -#include "mruby/string.h" - -int -main(void) -{ - mrb_float f = 0.09;// or double i = 0.09; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - -### mrb_fixnum_value - -```C -static inline mrb_value mrb_fixnum_value(mrb_int i) -``` - -Returns a fixnum in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 -could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_int i = 99; // or int i = 99; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_nil_value - -```C -static inline mrb_value mrb_nil_value(void) -``` - -Returns nil in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - -### mrb_false_value - -```C -static inline mrb_value mrb_false_value(void) -``` - -Returns false in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_true_value - -```C -static inline mrb_value mrb_true_value(void) -``` - -Returns true in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` -- cgit v1.2.3 From d768dcc42c1e62d82ef639012b7e748af105676e Mon Sep 17 00:00:00 2001 From: Mav7 Date: Thu, 4 Jun 2015 23:49:43 -0400 Subject: Adding an array readme markdown. --- doc/api/array.h.md | 0 doc/api/mruby/array.h.md | 0 doc/api/mruby/value.h.md | 233 ----------------------------------------------- doc/api/value.h.md | 233 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 233 deletions(-) create mode 100644 doc/api/array.h.md delete mode 100644 doc/api/mruby/array.h.md delete mode 100644 doc/api/mruby/value.h.md create mode 100644 doc/api/value.h.md diff --git a/doc/api/array.h.md b/doc/api/array.h.md new file mode 100644 index 000000000..e69de29bb diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/api/mruby/value.h.md b/doc/api/mruby/value.h.md deleted file mode 100644 index dd1c4b238..000000000 --- a/doc/api/mruby/value.h.md +++ /dev/null @@ -1,233 +0,0 @@ -### mrb_float_value -```C -static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) -``` - -Returns a float in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively -double i = 0.09 could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" -#include "mruby/string.h" - -int -main(void) -{ - mrb_float f = 0.09;// or double i = 0.09; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - -### mrb_fixnum_value - -```C -static inline mrb_value mrb_fixnum_value(mrb_int i) -``` - -Returns a fixnum in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 -could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_int i = 99; // or int i = 99; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_nil_value - -```C -static inline mrb_value mrb_nil_value(void) -``` - -Returns nil in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - -### mrb_false_value - -```C -static inline mrb_value mrb_false_value(void) -``` - -Returns false in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_true_value - -```C -static inline mrb_value mrb_true_value(void) -``` - -Returns true in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); - fclose(fp); - mrb_close(mrb); -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` diff --git a/doc/api/value.h.md b/doc/api/value.h.md new file mode 100644 index 000000000..dd1c4b238 --- /dev/null +++ b/doc/api/value.h.md @@ -0,0 +1,233 @@ +### mrb_float_value +```C +static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) +``` + +Returns a float in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively +double i = 0.09 could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" +#include "mruby/string.h" + +int +main(void) +{ + mrb_float f = 0.09;// or double i = 0.09; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + +### mrb_fixnum_value + +```C +static inline mrb_value mrb_fixnum_value(mrb_int i) +``` + +Returns a fixnum in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 +could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_int i = 99; // or int i = 99; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_nil_value + +```C +static inline mrb_value mrb_nil_value(void) +``` + +Returns nil in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + +### mrb_false_value + +```C +static inline mrb_value mrb_false_value(void) +``` + +Returns false in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_true_value + +```C +static inline mrb_value mrb_true_value(void) +``` + +Returns true in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); + fclose(fp); + mrb_close(mrb); +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` -- cgit v1.2.3 From e63962c0a4df07897fe31966a8d768fc994f6da7 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 4 Jun 2015 23:53:15 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index e69de29bb..d96d854b8 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -0,0 +1,2 @@ +### mrb_ary_new(mrb_state *mrb); +mrb_value mrb_ary_new(mrb_state *mrb); -- cgit v1.2.3 From 8a14073207dc43072003206be2b4f212d96051b2 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 4 Jun 2015 23:54:27 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index d96d854b8..d3f5a12fa 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -1,2 +1 @@ -### mrb_ary_new(mrb_state *mrb); -mrb_value mrb_ary_new(mrb_state *mrb); + -- cgit v1.2.3 From b9716c59c7f32664ad6c27487766e81be8bdc2b2 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 00:05:41 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index d3f5a12fa..717522c62 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -1 +1,14 @@ +### mrb_ary_new +```C +mrb_value mrb_ary_new(mrb_state *mrb); +``` + +Initializes an array. + +#### Example + +example.c +```C + +``` -- cgit v1.2.3 From 88342b2709d9b795faeda5ba9d526bf600d351e8 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 00:17:42 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index 717522c62..d3f5a12fa 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -1,14 +1 @@ -### mrb_ary_new -```C -mrb_value mrb_ary_new(mrb_state *mrb); -``` - -Initializes an array. - -#### Example - -example.c -```C - -``` -- cgit v1.2.3 From 12b307396a9696d253232e7ac7c3c3a1cb53430c Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 02:42:48 -0400 Subject: Added more function documentation for arrays. --- doc/api/array.h.md | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index d3f5a12fa..714eacda0 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -1 +1,251 @@ +### mrb_ary_new() +```C +mrb_value mrb_ary_new(mrb_state *mrb); +``` +Initializes an array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we are declaring a variable new_ary of data type mrb_value. Then we are initializing it with the mrb_ary_new function which only takes an mruby state as an argument. +```C +#include +#include +#include "mruby/array.h" // Need the array header. +#include "mruby/compile.h" + + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +### mrb_ary_push() +```C +void mrb_ary_push(mrb_state*, mrb_value, mrb_value); +``` +Pushes given value into an array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. +```C +#include +#include +#include "mruby/array.h" // Need the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60] +Array +``` + +## mrb_ary_pop() +```C +mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); +``` +Pops the last element from the array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. Now here in the Ruby files we add another method +called pop_ary that will return the array alone(just to be clean) and you should see the last element gone. +```C +#include +#include +#include "mruby/array.h" // Need the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60. + mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results. + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end + def pop_ary(a) + puts a + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60] +Array +[70] +``` +## mrb_ary_ref() +```C +mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); +``` +Returns a reference to an element of the array. Specified by the value given to mrb_int n. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. +```C +#include +#include +#include "mruby/array.h" // Need the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value ary_ref; // Declare variable. + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1. + mrb_value obj = mrb_load_file(mrb,fp); + /* Passing the value from ary_ref to the method method_name.*/ + mrb_funcall(mrb, obj, "method_name", 1, ary_ref); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +60 +Fixnum +``` + +### mrb_ary_set +```C +void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); +``` +Sets a value to an index. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. +```C +#include +#include +#include "mruby/array.h" // Need the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; + mrb_value ary_obj; + mrb_int random_value1 = 70; + mrb_int random_value2 = 60; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + /* Sets the fixnum value of 7 to the second index of the array.*/ + mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "before_after", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end + def before_after(a) + puts a + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60, 7] +``` -- cgit v1.2.3 From a3a18cd7a691b3382c41ae5e73ef85bcdbabca3d Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 02:43:54 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index 714eacda0..33466e149 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -1,4 +1,4 @@ -### mrb_ary_new() +### mrb_ary_new ```C mrb_value mrb_ary_new(mrb_state *mrb); @@ -38,7 +38,7 @@ end Example_Class.new ``` -### mrb_ary_push() +### mrb_ary_push ```C void mrb_ary_push(mrb_state*, mrb_value, mrb_value); ``` @@ -88,7 +88,7 @@ After compiling you should get these results. Array ``` -## mrb_ary_pop() +## mrb_ary_pop ```C mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); ``` @@ -144,7 +144,7 @@ After compiling you should get these results. Array [70] ``` -## mrb_ary_ref() +## mrb_ary_ref ```C mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); ``` -- cgit v1.2.3 From e1795cb72dad87c163a38a59915b86ac83c09563 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 02:51:37 -0400 Subject: Update value.h.md --- doc/api/value.h.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/api/value.h.md b/doc/api/value.h.md index dd1c4b238..f3ae2d421 100644 --- a/doc/api/value.h.md +++ b/doc/api/value.h.md @@ -30,6 +30,7 @@ main(void) mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); fclose(fp); mrb_close(mrb); + return 0; } ``` @@ -77,6 +78,7 @@ main(void) mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); fclose(fp); mrb_close(mrb); + return 0; } ``` @@ -124,6 +126,7 @@ main(void) mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); fclose(fp); mrb_close(mrb); + return 0; } ``` @@ -170,6 +173,7 @@ main(void) mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); fclose(fp); mrb_close(mrb); + return 0; } ``` @@ -217,6 +221,7 @@ main(void) mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); fclose(fp); mrb_close(mrb); + return 0; } ``` -- cgit v1.2.3 From 0f93d9b7dbdc74f485617051b5db81db09c7b726 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 5 Jun 2015 02:54:11 -0400 Subject: Update array.h.md --- doc/api/array.h.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/array.h.md b/doc/api/array.h.md index 33466e149..e1fb0003d 100644 --- a/doc/api/array.h.md +++ b/doc/api/array.h.md @@ -9,7 +9,7 @@ In this example we read from a Ruby file inside C. The Ruby code will print what ```C #include #include -#include "mruby/array.h" // Need the array header. +#include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" @@ -48,7 +48,7 @@ In this example we read from a Ruby file inside C. The Ruby code will print what ```C #include #include -#include "mruby/array.h" // Need the array header. +#include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" int main(int argc, char *argv[]) @@ -99,7 +99,7 @@ called pop_ary that will return the array alone(just to be clean) and you should ```C #include #include -#include "mruby/array.h" // Need the array header. +#include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" int main(int argc, char *argv[]) @@ -154,7 +154,7 @@ In this example we read from a Ruby file inside C. The Ruby code will print what ```C #include #include -#include "mruby/array.h" // Need the array header. +#include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" int main(int argc, char *argv[]) @@ -207,7 +207,7 @@ In this example we read from a Ruby file inside C. The Ruby code will print what ```C #include #include -#include "mruby/array.h" // Need the array header. +#include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" int main(int argc, char *argv[]) -- cgit v1.2.3 From 3bcf570a17d25783187c8aa3413bf48425b29619 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 6 Jun 2015 08:57:33 +0900 Subject: Fix build on MIPS of linux MIPS of Linux platform is supported frexpl(3). This fixes to use the frexpl that are provided with gcc if user wants to build on MIPS of Linux platform. Signe-doff-by: Nobuhiro Iwamatsu --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index ef2f19dd5..a634edb34 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -90,7 +90,7 @@ fmt_u(uint32_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -#if defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips) +#if (defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__) static long double frexpl (long double x, int *eptr) { -- cgit v1.2.3 From 5dd2b8e16f33b84773cdebeec4b6a86a511e8e9c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 8 Jun 2015 17:32:14 +0900 Subject: gsub/sub supports back references in substitutes. fixes #2816. This implementation is compatible with CRuby's String#gsub/sub except \1 ... \9 and \+. They are useless without Regexp library. --- mrblib/string.rb | 39 +++++++++++++++++++++++++++++++++++++-- test/t/string.rb | 18 ++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 90aad5d32..ee097ad6d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -20,6 +20,30 @@ class String self end + # private method for gsub/sub + def __sub_replace(pre, m, post) + s = "" + i = 0 + while j = index("\\", i) + break if j == length-1 + t = case self[j+1] + when "\\" + "\\" + when "`" + pre + when "&", "0" + m + when "'" + post + else + self[j, 2] + end + s += self[i, j-i] + t + i = j + 2 + end + s + self[i, length-i] + end + ## # Replace all matches of +pattern+ with +replacement+. # Call block (if given) for each match and replace @@ -29,7 +53,17 @@ class String # ISO 15.2.10.5.18 def gsub(*args, &block) if args.size == 2 - split(args[0], -1).join(args[1]) + s = "" + i = 0 + while j = index(args[0], i) + seplen = args[0].length + k = j + seplen + pre = self[0, j] + post = self[k, length-k] + s += self[i, j-i] + args[1].__sub_replace(pre, args[0], post) + i = k + end + s + self[i, length-i] elsif args.size == 1 && block split(args[0], -1).join(block.call(args[0])) else @@ -76,7 +110,8 @@ class String # ISO 15.2.10.5.36 def sub(*args, &block) if args.size == 2 - split(args[0], 2).join(args[1]) + pre, post = split(args[0], 2) + pre + args[1].__sub_replace(pre, args[0], post) + post elsif args.size == 1 && block split(args[0], 2).join(block.call(args[0])) else diff --git a/test/t/string.rb b/test/t/string.rb index 63e4af000..ee6fe0848 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -254,6 +254,15 @@ assert('String#gsub', '15.2.10.5.18') do assert_equal('A', 'a'.gsub('a'){|w| w.capitalize }) end +assert('String#gsub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cd<\\>ef', s.gsub('X', '<\\\\>') + assert_equal 'abcdef', s.gsub('X', '<\\&>') + assert_equal 'abcdef', s.gsub('X', '<\\0>') + assert_equal 'abcdef', s.gsub('X', '<\\`>') + assert_equal 'abcdef', s.gsub('X', '<\\\'>') +end + assert('String#gsub!', '15.2.10.5.19') do a = 'abcabc' a.gsub!('b', 'B') @@ -416,6 +425,15 @@ assert('String#sub', '15.2.10.5.36') do assert_equal 'aa$', 'aa#'.sub('#', '$') end +assert('String#sub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cdXef', s.sub('X', '<\\\\>') + assert_equal 'abcdXef', s.sub('X', '<\\&>') + assert_equal 'abcdXef', s.sub('X', '<\\0>') + assert_equal 'abcdXef', s.sub('X', '<\\`>') + assert_equal 'abcdXef', s.sub('X', '<\\\'>') +end + assert('String#sub!', '15.2.10.5.37') do a = 'abcabc' a.sub!('b', 'B') -- cgit v1.2.3 From be2c156876c5b6cd4c9937c2d266f1862597af58 Mon Sep 17 00:00:00 2001 From: Huei-Horng Yo Date: Tue, 9 Jun 2015 21:07:12 +0800 Subject: Detect if ncurses' backend is terminfo or termcap. fixes #2662 Borrowed from @mattn's code at: https://github.com/mruby/mruby/issues/2662#issuecomment-65535705 Signed-off-by: Huei-Horng Yo --- Rakefile | 1 + mrbgems/mruby-bin-mirb/mrbgem.rake | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index 0f33c5ee8..89dab05e7 100644 --- a/Rakefile +++ b/Rakefile @@ -3,6 +3,7 @@ # basic build file for mruby MRUBY_ROOT = File.dirname(File.expand_path(__FILE__)) MRUBY_BUILD_HOST_IS_CYGWIN = RUBY_PLATFORM.include?('cygwin') +MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd') # load build systems load "#{MRUBY_ROOT}/tasks/ruby_ext.rake" diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index 98df38499..e77114515 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -6,10 +6,16 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| if spec.build.cc.search_header_path 'readline/readline.h' spec.cc.defines << "ENABLE_READLINE" if spec.build.cc.search_header_path 'termcap.h' - if MRUBY_BUILD_HOST_IS_CYGWIN then - spec.linker.libraries << 'ncurses' - else - spec.linker.libraries << 'termcap' + if MRUBY_BUILD_HOST_IS_CYGWIN || MRUBY_BUILD_HOST_IS_OPENBSD + if spec.build.cc.search_header_path 'termcap.h' + if MRUBY_BUILD_HOST_IS_CYGWIN then + spec.linker.libraries << 'ncurses' + elsif spec.linker.has_library('libterminfo') then + spec.linker.libraries << 'terminfo' + else + spec.linker.libraries << 'termcap' + end + end end end if RUBY_PLATFORM.include?('netbsd') -- cgit v1.2.3 From 2f4f36b3343872e7797768b4cd5f7e6b6a4505bb Mon Sep 17 00:00:00 2001 From: Huei-Horng Yo Date: Wed, 10 Jun 2015 12:40:18 +0800 Subject: Remove unused libterminfo detection code. The detection code is unused even on OpenBSD 5.7, because of the standard installation is libtermcap be installed, not libterminfo. This fixes #2829 Tested on Arch Linux (x86_64) & OpenBSD 5.7 (amd64). Signed-off-by: Huei-Horng Yo --- mrbgems/mruby-bin-mirb/mrbgem.rake | 2 -- 1 file changed, 2 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index e77114515..dce832d98 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -10,8 +10,6 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| if spec.build.cc.search_header_path 'termcap.h' if MRUBY_BUILD_HOST_IS_CYGWIN then spec.linker.libraries << 'ncurses' - elsif spec.linker.has_library('libterminfo') then - spec.linker.libraries << 'terminfo' else spec.linker.libraries << 'termcap' end -- cgit v1.2.3 From 5e8d2a4b841d59ceab9f6fcf3ae294d93b8332b5 Mon Sep 17 00:00:00 2001 From: cremno Date: Sat, 13 Jun 2015 14:59:57 +0200 Subject: refactor code to call mrb_inspect() instead mrb_inspect() also calls mrb_obj_as_string() after #inspect to ensure the mrb_value is a string. --- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 6 +----- src/print.c | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 44ad9bb06..141ea151b 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -11,12 +11,8 @@ static void p(mrb_state *mrb, mrb_value obj) { - mrb_value val; + mrb_value val = mrb_inspect(mrb, obj); - val = mrb_funcall(mrb, obj, "inspect", 0); - if (!mrb_string_p(val)) { - val = mrb_obj_as_string(mrb, obj); - } fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); putc('\n', stdout); } diff --git a/src/print.c b/src/print.c index b43936b13..c7c1ccd39 100644 --- a/src/print.c +++ b/src/print.c @@ -27,12 +27,8 @@ MRB_API void mrb_p(mrb_state *mrb, mrb_value obj) { #ifdef ENABLE_STDIO - mrb_value val; + mrb_value val = mrb_inspect(mrb, obj); - val = mrb_funcall(mrb, obj, "inspect", 0); - if (!mrb_string_p(val)) { - val = mrb_obj_as_string(mrb, obj); - } printstr(mrb, val); putc('\n', stdout); #endif -- cgit v1.2.3 From 95fa22a65cf0866afaf3efd933a180509922f047 Mon Sep 17 00:00:00 2001 From: Lukas Joeressen Date: Mon, 15 Jun 2015 15:03:44 +0200 Subject: Rounding errors could make time_alloc imprecise --- mrbgems/mruby-time/src/time.c | 5 +++-- mrbgems/mruby-time/test/time.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b377f3e33..36bbbe00a 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -6,6 +6,7 @@ #include #include +#include #include "mruby.h" #include "mruby/class.h" #include "mruby/data.h" @@ -208,12 +209,12 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); } - tm->usec = (time_t)((sec - tm->sec) * 1.0e6 + usec); + tm->usec = (time_t)llrint((sec - tm->sec) * 1.0e6 + usec); while (tm->usec < 0) { tm->sec--; tm->usec += 1000000; } - while (tm->usec > 1000000) { + while (tm->usec >= 1000000) { tm->sec++; tm->usec -= 1000000; } diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index ba9b48fab..759e2881d 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -203,3 +203,11 @@ assert('day of week methods') do assert_false t.friday? assert_false t.saturday? end + +assert('2000 times 500us make a second') do + t = Time.utc 2015 + 2000.times do + t += 0.0005 + end + t.usec == 0 +end -- cgit v1.2.3 From 47c61cf5027ed46a51ef0a261c3192700700a350 Mon Sep 17 00:00:00 2001 From: Lukas Joeressen Date: Tue, 16 Jun 2015 09:24:27 +0200 Subject: Changed llrint to llround --- mrbgems/mruby-time/src/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 36bbbe00a..da3451d22 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,9 +4,9 @@ ** See Copyright Notice in mruby.h */ +#include #include #include -#include #include "mruby.h" #include "mruby/class.h" #include "mruby/data.h" @@ -209,7 +209,7 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); } - tm->usec = (time_t)llrint((sec - tm->sec) * 1.0e6 + usec); + tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); while (tm->usec < 0) { tm->sec--; tm->usec += 1000000; -- cgit v1.2.3 From 6a796cb4ccd53a35c93c89c1074d556186207966 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 17 Jun 2015 09:19:09 +0900 Subject: Added a check for 64 bit time_t overflow; based on a patch from @kext; close #2836 --- mrbgems/mruby-time/src/time.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index da3451d22..081e84c1c 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -201,11 +201,14 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); - tm->sec = (time_t)sec; if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) { goto out_of_range; } - else if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { + if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) { + goto out_of_range; + } + tm->sec = (time_t)sec; + if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); } -- cgit v1.2.3 From d1e6d647bd3a91d58567657471f3d945836cde85 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Fri, 19 Jun 2015 20:34:32 +0900 Subject: [ci skip] Remove some Srting#split samples mruby not support regexp, so remove these samples. --- src/string.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/string.c b/src/string.c index 16e7f9ffd..e3a359b49 100644 --- a/src/string.c +++ b/src/string.c @@ -1714,10 +1714,8 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) * " now's the time".split #=> ["now's", "the", "time"] * " now's the time".split(' ') #=> ["now's", "the", "time"] * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] - * "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"] * "hello".split(//) #=> ["h", "e", "l", "l", "o"] * "hello".split(//, 3) #=> ["h", "e", "llo"] - * "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"] * * "mellow yellow".split("ello") #=> ["m", "w y", "w"] * "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] -- cgit v1.2.3 From dcc316d3b84691f88158c3a3d2c43e612a995f6e Mon Sep 17 00:00:00 2001 From: Anton Davydov Date: Fri, 19 Jun 2015 15:52:23 +0300 Subject: Fix typos in documentation and error messages [skip ci] --- CONTRIBUTING.md | 2 +- mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | 2 +- mrbgems/mruby-fiber/src/fiber.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d4de00b9..6bababb89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ on-demand. #### Don't use C++ style comments - /* This is the prefered comment style */ + /* This is the preferred comment style */ Use C++ style comments only for temporary comment e.g. commenting out some code lines. diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c index b40915909..f52514851 100755 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -33,7 +33,7 @@ static help_msg help_msg_list[] = { "\n" "Continue program stopped by a breakpoint.\n" "If N, which is non negative value, is passed,\n" - "proceed program until the N-th breakpoint is comming.\n" + "proceed program until the N-th breakpoint is coming.\n" "If N is not passed, N is assumed 1.\n" }, { diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 2e5cd82e9..93b3f1227 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -167,7 +167,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr } } if (resume && c->status == MRB_FIBER_TRANSFERRED) { - mrb_raise(mrb, E_FIBER_ERROR, "resuming transfered fiber"); + mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber"); } if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) { mrb_raise(mrb, E_FIBER_ERROR, "double resume"); @@ -265,8 +265,8 @@ fiber_eq(mrb_state *mrb, mrb_value self) * call-seq: * fiber.transfer(args, ...) -> obj * - * Transfers control to reciever fiber of the method call. - * Unlike resume the reciever wouldn't be pushed to call + * Transfers control to receiver fiber of the method call. + * Unlike resume the receiver wouldn't be pushed to call * stack of fibers. Instead it will switch to the call stack of * transferring fiber. * When resuming a fiber that was transferred to another fiber it would -- cgit v1.2.3 From 111602319bdecde9a9cfbe74b48b3b93debc35df Mon Sep 17 00:00:00 2001 From: Anton Davydov Date: Sat, 20 Jun 2015 13:27:36 +0300 Subject: Fix repository link to mruby/mruby [skip ci] --- doc/debugger/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/debugger/README.md b/doc/debugger/README.md index 56230e429..a13e91cec 100755 --- a/doc/debugger/README.md +++ b/doc/debugger/README.md @@ -13,7 +13,7 @@ This file documents the mruby debugger ('mrdb') methods. The trunk of the mruby source tree, with the most recent mrdb, can be checked out with the following command: ```bash -$ git clone https://github.com/mruby-Forum/mruby.git +$ git clone https://github.com/mruby/mruby.git ``` To run the `make` command: -- cgit v1.2.3 From 8d54977d259137b61a4e391a3928374d1b29aca3 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 02:23:11 +0900 Subject: Add :mgem gem loader to load mrbgem from mgem-list ( https://github.com/mruby/mgem-list ). --- tasks/mruby_build_gem.rake | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index dbbade487..d9d2575bd 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -52,6 +52,26 @@ module MRuby else params[:git] = "https://bitbucket.org/#{params[:bitbucket]}.git" end + elsif params[:mgem] + mgem_list_dir = "#{gem_clone_dir}/mgem-list" + mgem_list_url = 'https://github.com/mruby/mgem-list.git' + if File.exist? mgem_list_dir + git.run_pull mgem_list_dir, mgem_list_url if $pull_gems + else + FileUtils.mkdir_p mgem_list_dir + git.run_clone mgem_list_dir, mgem_list_url + end + + require 'yaml' + + conf_path = "#{mgem_list_dir}/#{params[:mgem]}.gem" + conf_path = "#{mgem_list_dir}/mruby-#{params[:mgem]}.gem" unless File.exist? conf_path + fail "mgem not found: #{params[:mgem]}" unless File.exist? conf_path + conf = YAML.load File.read conf_path + + fail "unknown mgem protocol: #{conf['protocol']}" if conf['protocol'] != 'git' + params[:git] = conf['repository'] + params[:branch] = conf['branch"] if conf["branch'] end if params[:core] -- cgit v1.2.3 From 0c8fa845e4faf83c50b0df0272c58870832d9e62 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 02:23:52 +0900 Subject: Load missing dependencies from core or mgem-list. --- tasks/mrbgem_spec.rake | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index e6e17e182..e22a39e19 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -304,7 +304,14 @@ module MRuby default_gems = [] each do |g| g.dependencies.each do |dep| - default_gems << dep if dep[:default] and not gem_table.key? dep[:gem] + unless gem_table.key? dep[:gem] + if dep[:default]; default_gems << dep + elsif File.exist? "#{root}/mrbgems/#{dep[:gem]}" # check core + default_gems << { :gem => dep[:gem], :default => { :core => dep[:gem] } } + else # fallback to mgem-list + default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } } + end + end end end @@ -316,7 +323,11 @@ module MRuby spec.setup spec.dependencies.each do |dep| - default_gems << dep if dep[:default] and not gem_table.key? dep[:gem] + unless gem_table.key? dep[:gem] + if dep[:default]; default_gems << dep + else default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } } + end + end end gem_table[spec.name] = spec end -- cgit v1.2.3 From 078d24d4d3f7b5aac436fb70e341e1a7668fdbbb Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 02:24:15 +0900 Subject: Add documentation to new mgem features. --- doc/mrbgems/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index 101177b13..b24be74e0 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -26,6 +26,15 @@ conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master' conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master' ``` +To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option: +```ruby +conf.gem :mgem => 'mruby-yaml' +conf.gem :mgem => 'yaml' # 'mruby-' prefix could be ignored +``` + +If there is missing dependencies, mrbgem dependencies solver will reference +mrbgem from core or mgem-list. + To pull all gems from remote GIT repository on build, call ```./minirake -p```, or ```./minirake --pull-gems```. -- cgit v1.2.3 From e344c6ab6d7b3d6a8ffcec6f7f96aeba6c5fdeda Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 22 Jun 2015 10:09:04 +0900 Subject: [ci skip] replace "ignored" by "omitted"; ref #2846 --- doc/mrbgems/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index b24be74e0..e0c60daf2 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -29,7 +29,7 @@ conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master' To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option: ```ruby conf.gem :mgem => 'mruby-yaml' -conf.gem :mgem => 'yaml' # 'mruby-' prefix could be ignored +conf.gem :mgem => 'yaml' # 'mruby-' prefix could be omitted ``` If there is missing dependencies, mrbgem dependencies solver will reference @@ -151,7 +151,7 @@ MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| # Use any version of mruby-uv from github. spec.add_dependency('mruby-uv', '>= 0.0.0', :github => 'mattn/mruby-uv') - # Use latest mruby-onig-regexp from github. (version requirements can be ignored) + # Use latest mruby-onig-regexp from github. (version requirements can be omitted) spec.add_dependency('mruby-onig-regexp', :github => 'mattn/mruby-onig-regexp') end ``` -- cgit v1.2.3 From f0eaf9eaf53ce659c44ce6beeedbeb8bfc5b4efa Mon Sep 17 00:00:00 2001 From: cremno Date: Mon, 22 Jun 2015 13:34:24 +0200 Subject: fix arity of lambdas with optional arguments From the CRuby 2.2.2 Proc#arity documentation: If the block has optional arguments, returns -n-1, where n is the number of mandatory arguments, with the exception for blocks that are not lambdas and have only a finite number of optional arguments; in this latter case, returns n. --- src/proc.c | 2 +- test/t/proc.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/proc.c b/src/proc.c index 4cb9ffe18..61524f00c 100644 --- a/src/proc.c +++ b/src/proc.c @@ -216,7 +216,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) ma = MRB_ASPEC_REQ(aspec); ra = MRB_ASPEC_REST(aspec); pa = MRB_ASPEC_POST(aspec); - arity = ra ? -(ma + pa + 1) : ma + pa; + arity = ra || MRB_PROC_STRICT_P(p) ? -(ma + pa + 1) : ma + pa; return mrb_fixnum_value(arity); } diff --git a/test/t/proc.rb b/test/t/proc.rb index 22ccceb68..888b7d56a 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -36,6 +36,14 @@ assert('Proc#arity', '15.2.17.4.2') do assert_equal(-3, b) assert_equal 1, c assert_equal 1, d + + e = ->(x=0, y){}.arity + f = ->((x, y), z=0){}.arity + g = ->(x=0){}.arity + + assert_equal(-2, e) + assert_equal(-2, f) + assert_equal(-1, g) end assert('Proc#call', '15.2.17.4.3') do -- cgit v1.2.3 From 69b4c1648a71d7c275a98de7b9ebdc635a5fe438 Mon Sep 17 00:00:00 2001 From: cremno Date: Mon, 22 Jun 2015 16:35:54 +0200 Subject: Proc#curry should preserve lambdas --- mrbgems/mruby-proc-ext/mrblib/proc.rb | 4 +++- mrbgems/mruby-proc-ext/test/proc.rb | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-proc-ext/mrblib/proc.rb b/mrbgems/mruby-proc-ext/mrblib/proc.rb index 5dd9981df..b71663938 100644 --- a/mrbgems/mruby-proc-ext/mrblib/proc.rb +++ b/mrbgems/mruby-proc-ext/mrblib/proc.rb @@ -13,9 +13,11 @@ class Proc end def curry(arity=self.arity) + type = :proc abs = lambda {|a| a < 0 ? -a - 1 : a} arity = abs[arity] if lambda? + type = :lambda self_arity = self.arity if (self_arity >= 0 && arity != self_arity) || (self_arity < 0 && abs[self_arity] > arity) @@ -25,7 +27,7 @@ class Proc pproc = self make_curry = proc do |given_args=[]| - proc do |*args| + send(type) do |*args| new_args = given_args + args if new_args.size >= arity pproc[*new_args] diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index bca9b463a..75e11dd93 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -41,6 +41,9 @@ assert('Proc#curry') do assert_raise(ArgumentError) { b.curry[1, 2][3, 4] } assert_raise(ArgumentError) { b.curry(5) } assert_raise(ArgumentError) { b.curry(1) } + + assert_false(proc{}.curry.lambda?) + assert_true(lambda{}.curry.lambda?) end assert('Proc#parameters') do -- cgit v1.2.3 From 7e087d7191507b1ad5c47b6a621ec499e6010543 Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Mon, 22 Jun 2015 13:01:15 -0400 Subject: Need mruby-compiler to build mruby-bin-mruby and mruby-bin-mirb for cross compiles --- mrbgems/default.gembox | 3 +++ mrbgems/mruby-bin-mirb/mrbgem.rake | 1 + mrbgems/mruby-bin-mruby/mrbgem.rake | 1 + 3 files changed, 5 insertions(+) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 06609d9e7..30dcc1abc 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -70,4 +70,7 @@ MRuby::GemBox.new do |conf| # Use extensional Kernel module conf.gem :core => "mruby-kernel-ext" + + # Use mruby-compiler to build other mrbgems + conf.gem :core => "mruby-compiler" end diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index dce832d98..7d45409c9 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -26,4 +26,5 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| end spec.bins = %w(mirb) + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') end diff --git a/mrbgems/mruby-bin-mruby/mrbgem.rake b/mrbgems/mruby-bin-mruby/mrbgem.rake index 4e2f6a142..ba7fad1fa 100644 --- a/mrbgems/mruby-bin-mruby/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby/mrbgem.rake @@ -3,4 +3,5 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec| spec.author = 'mruby developers' spec.summary = 'mruby command' spec.bins = %w(mruby) + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') end -- cgit v1.2.3 From 338ca305ae558e4c6f929fdb619f586fb030ba7f Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 18:37:14 -0700 Subject: Calling mrb_str_to_str in mrb_string_value_cstr. Fixes #2847 --- src/string.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 0a28f2565..9a1a6fba1 100644 --- a/src/string.c +++ b/src/string.c @@ -1985,7 +1985,8 @@ bad: MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - struct RString *ps = mrb_str_ptr(*ptr); + mrb_value str = mrb_str_to_str(mrb, *ptr); + struct RString *ps = mrb_str_ptr(str); mrb_int len = mrb_str_strlen(mrb, ps); char *p = RSTR_PTR(ps); -- cgit v1.2.3 From 9553e20d34c204826fde86620d2f433b3d59f1c1 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 19:07:25 -0700 Subject: Removing redundant mrb_str_to_str call --- src/string.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/string.c b/src/string.c index 9a1a6fba1..9f753a0cf 100644 --- a/src/string.c +++ b/src/string.c @@ -2003,7 +2003,6 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; - str = mrb_str_to_str(mrb, str); if (badcheck) { s = mrb_string_value_cstr(mrb, &str); } -- cgit v1.2.3 From 264a059aef01b079d9788c8569182482edeab82a Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 19:15:52 -0700 Subject: Removing unneeded bad_checks for verified strings --- mrbgems/mruby-sprintf/src/sprintf.c | 2 +- src/object.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index d88e242c6..ca4ecfbbd 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -808,7 +808,7 @@ retry: if (mrb_fixnum_p(val)) goto bin_retry; break; case MRB_TT_STRING: - val = mrb_str_to_inum(mrb, val, 0, TRUE); + val = mrb_str_to_inum(mrb, val, 0, FALSE); goto bin_retry; case MRB_TT_FIXNUM: v = mrb_fixnum(val); diff --git a/src/object.c b/src/object.c index c5fb74575..df7d77b9e 100644 --- a/src/object.c +++ b/src/object.c @@ -539,7 +539,7 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) case MRB_TT_STRING: string_conv: - return mrb_str_to_inum(mrb, val, base, TRUE); + return mrb_str_to_inum(mrb, val, base, FALSE); default: break; -- cgit v1.2.3 From cfcca2a727e2af8aa789d7a29bbe612628e84893 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 19:49:12 -0700 Subject: Reverting overzealous changes --- mrbgems/mruby-sprintf/src/sprintf.c | 2 +- src/object.c | 2 +- src/string.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index ca4ecfbbd..d88e242c6 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -808,7 +808,7 @@ retry: if (mrb_fixnum_p(val)) goto bin_retry; break; case MRB_TT_STRING: - val = mrb_str_to_inum(mrb, val, 0, FALSE); + val = mrb_str_to_inum(mrb, val, 0, TRUE); goto bin_retry; case MRB_TT_FIXNUM: v = mrb_fixnum(val); diff --git a/src/object.c b/src/object.c index df7d77b9e..c5fb74575 100644 --- a/src/object.c +++ b/src/object.c @@ -539,7 +539,7 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) case MRB_TT_STRING: string_conv: - return mrb_str_to_inum(mrb, val, base, FALSE); + return mrb_str_to_inum(mrb, val, base, TRUE); default: break; diff --git a/src/string.c b/src/string.c index 9f753a0cf..9a1a6fba1 100644 --- a/src/string.c +++ b/src/string.c @@ -2003,6 +2003,7 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; + str = mrb_str_to_str(mrb, str); if (badcheck) { s = mrb_string_value_cstr(mrb, &str); } -- cgit v1.2.3 From 9ad632559efc6392d4650eedb27090ec27f78776 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 20:49:09 -0700 Subject: *Correctly* removing extra mrb_str_to_str call --- src/string.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/string.c b/src/string.c index 9a1a6fba1..22a289ade 100644 --- a/src/string.c +++ b/src/string.c @@ -2003,12 +2003,12 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; - str = mrb_str_to_str(mrb, str); if (badcheck) { + /* Raises if the string contains a null character (the badcheck) */ s = mrb_string_value_cstr(mrb, &str); } else { - s = RSTRING_PTR(str); + s = mrb_string_value_ptr(mrb, str); } if (s) { len = RSTRING_LEN(str); -- cgit v1.2.3 From 937b5b546201b874e7aba6a371f28456a784b39a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Jun 2015 14:42:58 +0900 Subject: fix Proc#curry test failure; ref #2848 --- src/proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/proc.c b/src/proc.c index 61524f00c..f98998f68 100644 --- a/src/proc.c +++ b/src/proc.c @@ -200,7 +200,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) struct RProc *p = mrb_proc_ptr(self); mrb_code *iseq = mrb_proc_iseq(mrb, p); mrb_aspec aspec; - int ma, ra, pa, arity; + int ma, op, ra, pa, arity; if (MRB_PROC_CFUNC_P(p)) { /* TODO cfunc aspec not implemented yet */ @@ -214,9 +214,10 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) aspec = GETARG_Ax(*iseq); ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); ra = MRB_ASPEC_REST(aspec); pa = MRB_ASPEC_POST(aspec); - arity = ra || MRB_PROC_STRICT_P(p) ? -(ma + pa + 1) : ma + pa; + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; return mrb_fixnum_value(arity); } -- cgit v1.2.3 From 9781580c7134fcee7bf5a6d4356bc47593549da8 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Mon, 22 Jun 2015 23:19:58 -0700 Subject: Fixes #912 --- src/class.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/class.c b/src/class.c index 35c3aa040..05b549b3e 100644 --- a/src/class.c +++ b/src/class.c @@ -1174,11 +1174,11 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * call-seq: * class.new(args, ...) -> obj * - * Calls allocate to create a new object of - * class's class, then invokes that object's - * initialize method, passing it args. - * This is the method that ends up getting called whenever - * an object is constructed using .new. + * Creates a new object of class's class, then + * invokes that object's initialize method, + * passing it args. This is the method that ends + * up getting called whenever an object is constructed using + * `.new`. * */ -- cgit v1.2.3 From e90f0d51a3b2ac52aa76fa3c8b803bcc75433468 Mon Sep 17 00:00:00 2001 From: furunkel Date: Tue, 23 Jun 2015 10:35:02 +0200 Subject: Move deprecated macros and functions to dedicated header file --- include/mruby.h | 15 +++++---------- include/mruby/deprecated.h | 10 ++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 include/mruby/deprecated.h diff --git a/include/mruby.h b/include/mruby.h index 6eb3af844..69bb21704 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -192,10 +192,13 @@ typedef struct mrb_state { # define mrb_noreturn _Noreturn #elif defined __GNUC__ && !defined __STRICT_ANSI__ # define mrb_noreturn __attribute__((noreturn)) +# define mrb_deprecated __attribute__((deprecated)) #elif defined _MSC_VER # define mrb_noreturn __declspec(noreturn) +# define mrb_deprecated __declspec(deprecated) #else # define mrb_noreturn +# define mrb_deprecated #endif typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value); @@ -250,16 +253,6 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o /* accept no arguments */ #define MRB_ARGS_NONE() ((mrb_aspec)0) -/* compatibility macros; will be removed */ -#define ARGS_REQ(n) MRB_ARGS_REQ(n) -#define ARGS_OPT(n) MRB_ARGS_OPT(n) -#define ARGS_REST() MRB_ARGS_REST() -#define ARGS_POST(n) MRB_ARGS_POST() -#define ARGS_KEY(n1,n2) MRB_ARGS_KEY(n1,n2) -#define ARGS_BLOCK() MRB_ARGS_BLOCK() -#define ARGS_ANY() MRB_ARGS_ANY() -#define ARGS_NONE() MRB_ARGS_NONE() - MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...); /* `strlen` for character string literals (use with caution or `strlen` instead) @@ -459,6 +452,8 @@ MRB_API void mrb_show_copyright(mrb_state *mrb); MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...); +#include "mruby/deprecated.h" + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/include/mruby/deprecated.h b/include/mruby/deprecated.h new file mode 100644 index 000000000..ac1c81b7e --- /dev/null +++ b/include/mruby/deprecated.h @@ -0,0 +1,10 @@ +/* Deprecated macros and functions */ + +#define ARGS_REQ(n) MRB_ARGS_REQ(n) +#define ARGS_OPT(n) MRB_ARGS_OPT(n) +#define ARGS_REST() MRB_ARGS_REST() +#define ARGS_POST(n) MRB_ARGS_POST() +#define ARGS_KEY(n1,n2) MRB_ARGS_KEY(n1,n2) +#define ARGS_BLOCK() MRB_ARGS_BLOCK() +#define ARGS_ANY() MRB_ARGS_ANY() +#define ARGS_NONE() MRB_ARGS_NONE() -- cgit v1.2.3 From 6ed64e23678620f99e836eb07a58903760cf657c Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 23 Jun 2015 12:44:28 +0200 Subject: rewrite printstr() to get rid of code duplication --- src/print.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/src/print.c b/src/print.c index c7c1ccd39..077fa4f06 100644 --- a/src/print.c +++ b/src/print.c @@ -8,45 +8,35 @@ #include "mruby/string.h" #include "mruby/variable.h" +#ifdef ENABLE_STDIO static void -printstr(mrb_state *mrb, mrb_value obj) +printstr(mrb_value obj, FILE *stream) { -#ifdef ENABLE_STDIO - char *s; - int len; - if (mrb_string_p(obj)) { - s = RSTRING_PTR(obj); - len = RSTRING_LEN(obj); - fwrite(s, len, 1, stdout); + fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stream); + putc('\n', stream); } -#endif } +#else +# define printstr(obj, stream) (void)0 +#endif MRB_API void mrb_p(mrb_state *mrb, mrb_value obj) { -#ifdef ENABLE_STDIO mrb_value val = mrb_inspect(mrb, obj); - printstr(mrb, val); - putc('\n', stdout); -#endif + printstr(val, stdout); } MRB_API void mrb_print_error(mrb_state *mrb) { -#ifdef ENABLE_STDIO mrb_value s; mrb_print_backtrace(mrb); s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); - if (mrb_string_p(s)) { - fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr); - putc('\n', stderr); - } -#endif + printstr(s, stderr); } MRB_API void @@ -55,8 +45,7 @@ mrb_show_version(mrb_state *mrb) mrb_value msg; msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION")); - printstr(mrb, msg); - printstr(mrb, mrb_str_new_lit(mrb, "\n")); + printstr(msg, stdout); } MRB_API void @@ -65,6 +54,5 @@ mrb_show_copyright(mrb_state *mrb) mrb_value msg; msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")); - printstr(mrb, msg); - printstr(mrb, mrb_str_new_lit(mrb, "\n")); + printstr(msg, stdout); } -- cgit v1.2.3 From 0006a8cd4a15e52de7bb02fc89287183f2ef2209 Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Tue, 23 Jun 2015 12:35:31 -0400 Subject: add host_target/build_target options for CrossBuild'ng native extensions --- tasks/mruby_build.rake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 50bed0fbe..947b4ba77 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -283,6 +283,10 @@ EOS class CrossBuild < Build attr_block %w(test_runner) + # cross compiling targets for building native extensions. + # host - arch of where the built binary will run + # build - arch of the machine building the binary + attr_accessor :host_target, :build_target def initialize(name, build_dir=nil, &block) @test_runner = Command::CrossTestRunner.new(self) -- cgit v1.2.3 From e88e7dc8db4ff129de6698727fd87904b67ed0e0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Jun 2015 10:05:05 +0900 Subject: remove deprecated.h --- include/mruby.h | 2 -- include/mruby/deprecated.h | 10 ---------- 2 files changed, 12 deletions(-) delete mode 100644 include/mruby/deprecated.h diff --git a/include/mruby.h b/include/mruby.h index 69bb21704..1b792ce90 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -452,8 +452,6 @@ MRB_API void mrb_show_copyright(mrb_state *mrb); MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...); -#include "mruby/deprecated.h" - #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/include/mruby/deprecated.h b/include/mruby/deprecated.h deleted file mode 100644 index ac1c81b7e..000000000 --- a/include/mruby/deprecated.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Deprecated macros and functions */ - -#define ARGS_REQ(n) MRB_ARGS_REQ(n) -#define ARGS_OPT(n) MRB_ARGS_OPT(n) -#define ARGS_REST() MRB_ARGS_REST() -#define ARGS_POST(n) MRB_ARGS_POST() -#define ARGS_KEY(n1,n2) MRB_ARGS_KEY(n1,n2) -#define ARGS_BLOCK() MRB_ARGS_BLOCK() -#define ARGS_ANY() MRB_ARGS_ANY() -#define ARGS_NONE() MRB_ARGS_NONE() -- cgit v1.2.3 From 25885072858582d3d2f985b405a8e84d58f716e8 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Wed, 24 Jun 2015 13:07:07 +0200 Subject: Remove unnecessary backticks. Dr Markus Kuhn published in 1999 an article [1] explaining in details why we shouldn't use the ASCII grave accent (0x60) as a left quotation. Backticks have been used most notably to produce nice-looking LaTeX documents but it doesn't seem to be an issue on modern platforms and for the oldest ones, there are workarounds as mentioned by Dr Kuhn. [1]: https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html --- include/mruby/compile.h | 4 +- include/mruby/opcode.h | 2 +- mrbgems/mruby-compiler/core/parse.y | 14 +++--- mrbgems/mruby-hash-ext/mrblib/hash.rb | 2 +- mrbgems/mruby-sprintf/src/sprintf.c | 80 +++++++++++++++++------------------ mrbgems/mruby-struct/src/struct.c | 8 ++-- mrblib/array.rb | 2 +- src/class.c | 8 ++-- src/numeric.c | 4 +- src/object.c | 2 +- src/string.c | 6 +-- src/variable.c | 2 +- 12 files changed, 67 insertions(+), 67 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index e20473298..1fb81782d 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -55,8 +55,8 @@ enum mrb_lex_state_enum { EXPR_CMDARG, /* newline significant, +/- is an operator. */ EXPR_MID, /* newline significant, +/- is an operator. */ EXPR_FNAME, /* ignore newline, no reserved words. */ - EXPR_DOT, /* right after `.' or `::', no reserved words. */ - EXPR_CLASS, /* immediate after `class', no here document. */ + EXPR_DOT, /* right after '.' or '::', no reserved words. */ + EXPR_CLASS, /* immediate after 'class', no here document. */ EXPR_VALUE, /* alike EXPR_BEG but label is disallowed. */ EXPR_MAX_STATE }; diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h index 4774e78c6..9dfa7f75d 100644 --- a/include/mruby/opcode.h +++ b/include/mruby/opcode.h @@ -8,7 +8,7 @@ #define MRUBY_OPCODE_H #define MAXARG_Bx (0xffff) -#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ +#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ /* instructions: packed 32 bit */ /* ------------------------------- */ diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 5b17649a9..f6a43d32b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4204,7 +4204,7 @@ parser_yylex(parser_state *p) } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`*' interpreted as argument prefix"); + yywarning(p, "'*' interpreted as argument prefix"); c = tSTAR; } else if (IS_BEG()) { @@ -4455,7 +4455,7 @@ parser_yylex(parser_state *p) } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`&' interpreted as argument prefix"); + yywarning(p, "'&' interpreted as argument prefix"); c = tAMPER; } else if (IS_BEG()) { @@ -4761,7 +4761,7 @@ parser_yylex(parser_state *p) nondigit = c; break; - case '_': /* `_' in number just ignored */ + case '_': /* '_' in number just ignored */ if (nondigit) goto decode_num; nondigit = c; break; @@ -4776,7 +4776,7 @@ parser_yylex(parser_state *p) pushback(p, c); if (nondigit) { trailing_uc: - yyerror_i(p, "trailing `%c' in number", nondigit); + yyerror_i(p, "trailing '%c' in number", nondigit); } tokfix(p); if (is_float) { @@ -5157,10 +5157,10 @@ parser_yylex(parser_state *p) } else if (isdigit(c)) { if (p->bidx == 1) { - yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); } else { - yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + yyerror_i(p, "'@@%c' is not allowed as a class variable name", c); } return 0; } @@ -5176,7 +5176,7 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - yyerror_i(p, "Invalid char `\\x%02X' in expression", c); + yyerror_i(p, "Invalid char '\\x%02X' in expression", c); goto retry; } diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index ea5e6bc1b..c970b9d02 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -119,7 +119,7 @@ class Hash # # produces: # - # prog.rb:2:in `fetch': key not found (KeyError) + # prog.rb:2:in 'fetch': key not found (KeyError) # from prog.rb:2 # diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index d88e242c6..de216f69f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -234,20 +234,20 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * ------+-------------------------------------------------------------- * b | Convert argument as a binary number. * | Negative numbers will be displayed as a two's complement - * | prefixed with `..1'. - * B | Equivalent to `b', but uses an uppercase 0B for prefix + * | prefixed with '..1'. + * B | Equivalent to 'b', but uses an uppercase 0B for prefix * | in the alternative format by #. * d | Convert argument as a decimal number. - * i | Identical to `d'. + * i | Identical to 'd'. * o | Convert argument as an octal number. * | Negative numbers will be displayed as a two's complement - * | prefixed with `..7'. - * u | Identical to `d'. + * | prefixed with '..7'. + * u | Identical to 'd'. * x | Convert argument as a hexadecimal number. * | Negative numbers will be displayed as a two's complement - * | prefixed with `..f' (representing an infinite string of + * | prefixed with '..f' (representing an infinite string of * | leading 'ff's). - * X | Equivalent to `x', but uses uppercase letters. + * X | Equivalent to 'x', but uses uppercase letters. * * Field | Float Format * ------+-------------------------------------------------------------- @@ -255,7 +255,7 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * | with one digit before the decimal point as [-]d.dddddde[+-]dd. * | The precision specifies the number of digits after the decimal * | point (defaulting to six). - * E | Equivalent to `e', but uses an uppercase E to indicate + * E | Equivalent to 'e', but uses an uppercase E to indicate * | the exponent. * f | Convert floating point argument as [-]ddd.dddddd, * | where the precision specifies the number of digits after @@ -264,11 +264,11 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * | if the exponent is less than -4 or greater than or * | equal to the precision, or in dd.dddd form otherwise. * | The precision specifies the number of significant digits. - * G | Equivalent to `g', but use an uppercase `E' in exponent form. + * G | Equivalent to 'g', but use an uppercase 'E' in exponent form. * a | Convert floating point argument as [-]0xh.hhhhp[+-]dd, * | which is consisted from optional sign, "0x", fraction part * | as hexadecimal, "p", and exponential part as decimal. - * A | Equivalent to `a', but use uppercase `X' and `P'. + * A | Equivalent to 'a', but use uppercase 'X' and 'P'. * * Field | Other Format * ------+-------------------------------------------------------------- @@ -287,7 +287,7 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * ---------+---------------+----------------------------------------- * space | bBdiouxX | Leave a space at the start of * | aAeEfgG | non-negative numbers. - * | (numeric fmt) | For `o', `x', `X', `b' and `B', use + * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use * | | a minus sign with absolute value for * | | negative values. * ---------+---------------+----------------------------------------- @@ -297,27 +297,27 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * | | sprintf string. * ---------+---------------+----------------------------------------- * # | bBoxX | Use an alternative format. - * | aAeEfgG | For the conversions `o', increase the precision - * | | until the first digit will be `0' if + * | aAeEfgG | For the conversions 'o', increase the precision + * | | until the first digit will be '0' if * | | it is not formatted as complements. - * | | For the conversions `x', `X', `b' and `B' - * | | on non-zero, prefix the result with ``0x'', - * | | ``0X'', ``0b'' and ``0B'', respectively. - * | | For `a', `A', `e', `E', `f', `g', and 'G', + * | | For the conversions 'x', 'X', 'b' and 'B' + * | | on non-zero, prefix the result with "0x", + * | | "0X", "0b" and "0B", respectively. + * | | For 'a', 'A', 'e', 'E', 'f', 'g', and 'G', * | | force a decimal point to be added, * | | even if no digits follow. - * | | For `g' and 'G', do not remove trailing zeros. + * | | For 'g' and 'G', do not remove trailing zeros. * ---------+---------------+----------------------------------------- * + | bBdiouxX | Add a leading plus sign to non-negative * | aAeEfgG | numbers. - * | (numeric fmt) | For `o', `x', `X', `b' and `B', use + * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use * | | a minus sign with absolute value for * | | negative values. * ---------+---------------+----------------------------------------- * - | all | Left-justify the result of this conversion. * ---------+---------------+----------------------------------------- * 0 (zero) | bBdiouxX | Pad with zeros, not spaces. - * | aAeEfgG | For `o', `x', `X', `b' and `B', radix-1 + * | aAeEfgG | For 'o', 'x', 'X', 'b' and 'B', radix-1 * | (numeric fmt) | is used for negative numbers formatted as * | | complements. * ---------+---------------+----------------------------------------- @@ -328,21 +328,21 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * * Examples of flags: * - * # `+' and space flag specifies the sign of non-negative numbers. + * # '+' and space flag specifies the sign of non-negative numbers. * sprintf("%d", 123) #=> "123" * sprintf("%+d", 123) #=> "+123" * sprintf("% d", 123) #=> " 123" * - * # `#' flag for `o' increases number of digits to show `0'. - * # `+' and space flag changes format of negative numbers. + * # '#' flag for 'o' increases number of digits to show '0'. + * # '+' and space flag changes format of negative numbers. * sprintf("%o", 123) #=> "173" * sprintf("%#o", 123) #=> "0173" * sprintf("%+o", -123) #=> "-173" * sprintf("%o", -123) #=> "..7605" * sprintf("%#o", -123) #=> "..7605" * - * # `#' flag for `x' add a prefix `0x' for non-zero numbers. - * # `+' and space flag disables complements for negative numbers. + * # '#' flag for 'x' add a prefix '0x' for non-zero numbers. + * # '+' and space flag disables complements for negative numbers. * sprintf("%x", 123) #=> "7b" * sprintf("%#x", 123) #=> "0x7b" * sprintf("%+x", -123) #=> "-7b" @@ -350,12 +350,12 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * sprintf("%#x", -123) #=> "0x..f85" * sprintf("%#x", 0) #=> "0" * - * # `#' for `X' uses the prefix `0X'. + * # '#' for 'X' uses the prefix '0X'. * sprintf("%X", 123) #=> "7B" * sprintf("%#X", 123) #=> "0X7B" * - * # `#' flag for `b' add a prefix `0b' for non-zero numbers. - * # `+' and space flag disables complements for negative numbers. + * # '#' flag for 'b' add a prefix '0b' for non-zero numbers. + * # '+' and space flag disables complements for negative numbers. * sprintf("%b", 123) #=> "1111011" * sprintf("%#b", 123) #=> "0b1111011" * sprintf("%+b", -123) #=> "-1111011" @@ -363,19 +363,19 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * sprintf("%#b", -123) #=> "0b..10000101" * sprintf("%#b", 0) #=> "0" * - * # `#' for `B' uses the prefix `0B'. + * # '#' for 'B' uses the prefix '0B'. * sprintf("%B", 123) #=> "1111011" * sprintf("%#B", 123) #=> "0B1111011" * - * # `#' for `e' forces to show the decimal point. + * # '#' for 'e' forces to show the decimal point. * sprintf("%.0e", 1) #=> "1e+00" * sprintf("%#.0e", 1) #=> "1.e+00" * - * # `#' for `f' forces to show the decimal point. + * # '#' for 'f' forces to show the decimal point. * sprintf("%.0f", 1234) #=> "1234" * sprintf("%#.0f", 1234) #=> "1234." * - * # `#' for `g' forces to show the decimal point. + * # '#' for 'g' forces to show the decimal point. * # It also disables stripping lowest zeros. * sprintf("%g", 123.4) #=> "123.4" * sprintf("%#g", 123.4) #=> "123.400" @@ -409,7 +409,7 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * * Examples of precisions: * - * # precision for `d', 'o', 'x' and 'b' is + * # precision for 'd', 'o', 'x' and 'b' is * # minimum number of digits <------> * sprintf("%20.8d", 123) #=> " 00000123" * sprintf("%20.8o", 123) #=> " 00000173" @@ -420,8 +420,8 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * sprintf("%20.8x", -123) #=> " ..ffff85" * sprintf("%20.8b", -11) #=> " ..110101" * - * # "0x" and "0b" for `#x' and `#b' is not counted for - * # precision but "0" for `#o' is counted. <------> + * # "0x" and "0b" for '#x' and '#b' is not counted for + * # precision but "0" for '#o' is counted. <------> * sprintf("%#20.8d", 123) #=> " 00000123" * sprintf("%#20.8o", 123) #=> " 00000173" * sprintf("%#20.8x", 123) #=> " 0x0000007b" @@ -431,22 +431,22 @@ get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) * sprintf("%#20.8x", -123) #=> " 0x..ffff85" * sprintf("%#20.8b", -11) #=> " 0b..110101" * - * # precision for `e' is number of + * # precision for 'e' is number of * # digits after the decimal point <------> * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03" * - * # precision for `f' is number of + * # precision for 'f' is number of * # digits after the decimal point <------> * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000" * - * # precision for `g' is number of + * # precision for 'g' is number of * # significant digits <-------> * sprintf("%20.8g", 1234.56789) #=> " 1234.5679" * * # <-------> * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08" * - * # precision for `s' is + * # precision for 's' is * # maximum number of characters <------> * sprintf("%20.8s", "string test") #=> " string t" * @@ -539,7 +539,7 @@ mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt) if (t >= end) goto sprint_exit; /* end of fmt string */ - p = t + 1; /* skip `%' */ + p = t + 1; /* skip '%' */ width = prec = -1; nextvalue = mrb_undef_value(); diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index d2187a2d1..ce8d8d832 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -114,7 +114,7 @@ mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id) return ptr[i]; } } - mrb_raisef(mrb, E_INDEX_ERROR, "`%S' is not a struct member", mrb_sym2str(mrb, id)); + mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id)); return mrb_nil_value(); /* not reached */ } @@ -193,7 +193,7 @@ mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val) return ptr[i] = val; } } - mrb_raisef(mrb, E_INDEX_ERROR, "`%S' is not a struct member", mrb_sym2str(mrb, mid)); + mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, mid)); return mrb_nil_value(); /* not reached */ } @@ -749,8 +749,8 @@ mrb_struct_values_at(mrb_state *mrb, mrb_value self) * The Struct class is a generator of specific classes, * each one of which is defined to hold a set of variables and their * accessors. In these examples, we'll call the generated class - * ``CustomerClass,'' and we'll show an example instance of that - * class as ``CustomerInst.'' + * "CustomerClass," and we'll show an example instance of that + * class as "CustomerInst." * * In the descriptions that follow, the parameter symbol refers * to a symbol, which is either a quoted string or a diff --git a/mrblib/array.rb b/mrblib/array.rb index 83a42c62d..933f822db 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -146,7 +146,7 @@ class Array # equal, then that inequality is the return value. If all the # values found are equal, then the return is based on a # comparison of the array lengths. Thus, two arrays are - # ``equal'' according to Array#<=> if and only if they have + # "equal" according to Array#<=> if and only if they have # the same length and the value of each element is equal to the # value of the corresponding element in the other array. # diff --git a/src/class.c b/src/class.c index 05b549b3e..e9cbc592d 100644 --- a/src/class.c +++ b/src/class.c @@ -212,7 +212,7 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { - mrb_warn(mrb, "no super class for `%S', Object assumed", mrb_sym2str(mrb, name)); + mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); } return define_class(mrb, name, super, mrb->object_class); } @@ -311,7 +311,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s #if 0 if (!super) { - mrb_warn(mrb, "no super class for `%S::%S', Object assumed", + mrb_warn(mrb, "no super class for '%S::%S', Object assumed", mrb_obj_value(outer), mrb_sym2str(mrb, id)); } #endif @@ -1658,7 +1658,7 @@ check_cv_name_str(mrb_state *mrb, mrb_value str) mrb_int len = RSTRING_LEN(str); if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "`%S' is not allowed as a class variable name", str); + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); } } @@ -1846,7 +1846,7 @@ remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) } } - mrb_name_error(mrb, mid, "method `%S' not defined in %S", + mrb_name_error(mrb, mid, "method '%S' not defined in %S", mrb_sym2str(mrb, mid), mod); } diff --git a/src/numeric.c b/src/numeric.c index 8b6ec4c88..013273232 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -110,8 +110,8 @@ num_div(mrb_state *mrb, mrb_value x) * * Returns a string containing a representation of self. As well as a * fixed or exponential form of the number, the call may return - * ``NaN'', ``Infinity'', and - * ``-Infinity''. + * "NaN", "Infinity", and + * "-Infinity". */ static mrb_value diff --git a/src/object.c b/src/object.c index c5fb74575..f8f41bfe8 100644 --- a/src/object.c +++ b/src/object.c @@ -428,7 +428,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) * Returns a string representing obj. The default * to_s prints the object's class and an encoding of the * object id. As a special case, the top-level object that is the - * initial execution context of Ruby programs returns ``main.'' + * initial execution context of Ruby programs returns "main." */ MRB_API mrb_value diff --git a/src/string.c b/src/string.c index 22a289ade..8df79d4c0 100644 --- a/src/string.c +++ b/src/string.c @@ -1100,7 +1100,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of str with all uppercase letters replaced with their * lowercase counterparts. The operation is locale insensitive---only - * characters ``A'' to ``Z'' are affected. + * characters 'A' to 'Z' are affected. * * "hEllO".downcase #=> "hello" */ @@ -1703,7 +1703,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) * * If pattern is omitted, the value of $; is used. If * $; is nil (which is the default), str is - * split on whitespace as if ` ' were specified. + * split on whitespace as if ' ' were specified. * * If the limit parameter is omitted, trailing null fields are * suppressed. If limit is a positive number, at most that number of @@ -2211,7 +2211,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of str with all lowercase letters replaced with their * uppercase counterparts. The operation is locale insensitive---only - * characters ``a'' to ``z'' are affected. + * characters 'a' to 'z' are affected. * * "hEllO".upcase #=> "HELLO" */ diff --git a/src/variable.c b/src/variable.c index 3e451df05..1b2ad56a7 100644 --- a/src/variable.c +++ b/src/variable.c @@ -563,7 +563,7 @@ MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) { if (!mrb_iv_p(mrb, iv_name)) { - mrb_name_error(mrb, iv_name, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } -- cgit v1.2.3 From a15e99d2b62127e05df50d6c9ba00d42e1de731f Mon Sep 17 00:00:00 2001 From: mattn Date: Thu, 25 Jun 2015 00:19:04 +0900 Subject: add_dependency doesn't work --- tasks/mrbgem_spec.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index e22a39e19..04a9c39f0 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -306,7 +306,7 @@ module MRuby g.dependencies.each do |dep| unless gem_table.key? dep[:gem] if dep[:default]; default_gems << dep - elsif File.exist? "#{root}/mrbgems/#{dep[:gem]}" # check core + elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core default_gems << { :gem => dep[:gem], :default => { :core => dep[:gem] } } else # fallback to mgem-list default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } } -- cgit v1.2.3 From 427cc64de0d3db4fa4c03d14c2785c37f91da12b Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Fri, 26 Jun 2015 14:37:57 +0200 Subject: Respect the directory structure of `include` As mentioned in the README, two files have been put under the `mruby` directory. --- doc/api/README.md | 40 ++++---- doc/api/array.h.md | 251 ----------------------------------------------- doc/api/mruby/array.h.md | 251 +++++++++++++++++++++++++++++++++++++++++++++++ doc/api/mruby/value.h.md | 238 ++++++++++++++++++++++++++++++++++++++++++++ doc/api/value.h.md | 238 -------------------------------------------- 5 files changed, 509 insertions(+), 509 deletions(-) delete mode 100644 doc/api/array.h.md create mode 100644 doc/api/mruby/array.h.md create mode 100644 doc/api/mruby/value.h.md delete mode 100644 doc/api/value.h.md diff --git a/doc/api/README.md b/doc/api/README.md index 131e50515..a83330d82 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -8,23 +8,23 @@ Header name|Features -----------|-------- [mrbconf.h](../mrbconf/README.md)|Defines macros for mruby configurations. [mruby.h](./mruby.h.md)|Main header of mruby C API. Include this first. -[mruby/array.h](./mruby.array.h.md)|`Array` class. -[mruby/class.h](./mruby.class.h.md)|`Class` class. -[mruby/compile.h](./mruby.compile.h.md)|mruby compiler. -[mruby/data.h](./mruby.data.h.md)|User defined object. -[mruby/debug.h](./mruby.debug.h.md)|Debugging. -[mruby/dump.h](./mruby.dump.h.md)|Dumping compiled mruby script. -[mruby/error.h](./mruby.error.h.md)|Error handling. -[mruby/gc.h](./mruby.gc.h.md)|Uncommon memory management stuffs. -[mruby/hash.h](./mruby.hash.h.md)|`Hash` class. -[mruby/irep.h](./mruby.irep.h.md)|Compiled mruby script. -[mruby/khash.h](./mruby.khash.h.md)|Defines of khash which is used in hash table of mruby. -[mruby/numeric.h](./mruby.numeric.h.md)|`Numeric` class and sub-classes of it. -[mruby/opode.h](./mruby.opcode.h.md)|Operation codes used in mruby VM. -[mruby/proc.h](./mruby.proc.h.md)|`Proc` class. -[mruby/range.h](./mruby.range.h.md)|`Range` class. -[mruby/re.h](./mruby.re.h.md)|`Regexp` class. -[mruby/string.h](./mruby.string.h.md)|`String` class. -[mruby/value.h](./mruby.value.h.md)|`mrb_value` functions and macros. -[mruby/variable.h](./mruby.variable.h.md)|Functions to access to mruby variables. -[mruby/version.h](./mruby.version.h.md)|Macros of mruby version. +[mruby/array.h](./mruby/array.h.md)|`Array` class. +[mruby/class.h](./mruby/class.h.md)|`Class` class. +[mruby/compile.h](./mruby/compile.h.md)|mruby compiler. +[mruby/data.h](./mruby/data.h.md)|User defined object. +[mruby/debug.h](./mruby/debug.h.md)|Debugging. +[mruby/dump.h](./mruby/dump.h.md)|Dumping compiled mruby script. +[mruby/error.h](./mruby/error.h.md)|Error handling. +[mruby/gc.h](./mruby/gc.h.md)|Uncommon memory management stuffs. +[mruby/hash.h](./mruby/hash.h.md)|`Hash` class. +[mruby/irep.h](./mruby/irep.h.md)|Compiled mruby script. +[mruby/khash.h](./mruby/khash.h.md)|Defines of khash which is used in hash table of mruby. +[mruby/numeric.h](./mruby/numeric.h.md)|`Numeric` class and sub-classes of it. +[mruby/opode.h](./mruby/opcode.h.md)|Operation codes used in mruby VM. +[mruby/proc.h](./mruby/proc.h.md)|`Proc` class. +[mruby/range.h](./mruby/range.h.md)|`Range` class. +[mruby/re.h](./mruby/re.h.md)|`Regexp` class. +[mruby/string.h](./mruby/string.h.md)|`String` class. +[mruby/value.h](./mruby/value.h.md)|`mrb_value` functions and macros. +[mruby/variable.h](./mruby/variable.h.md)|Functions to access to mruby variables. +[mruby/version.h](./mruby/version.h.md)|Macros of mruby version. diff --git a/doc/api/array.h.md b/doc/api/array.h.md deleted file mode 100644 index e1fb0003d..000000000 --- a/doc/api/array.h.md +++ /dev/null @@ -1,251 +0,0 @@ -### mrb_ary_new - -```C -mrb_value mrb_ary_new(mrb_state *mrb); -``` -Initializes an array. -#### Example -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we are declaring a variable new_ary of data type mrb_value. Then we are initializing it with the mrb_ary_new function which only takes an mruby state as an argument. -```C -#include -#include -#include "mruby/array.h" // Needs the array header. -#include "mruby/compile.h" - - -int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; -} -``` -test.rb -```Ruby -class Example_Class - def method_name(a) - puts a - puts a.class - end -end -Example_Class.new -``` - -### mrb_ary_push -```C -void mrb_ary_push(mrb_state*, mrb_value, mrb_value); -``` -Pushes given value into an array. -#### Example -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. -```C -#include -#include -#include "mruby/array.h" // Needs the array header. -#include "mruby/compile.h" - -int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; -} -``` -test.rb -```Ruby -class Example_Class - def method_name(a) - puts a - puts a.class - end -end -Example_Class.new -``` -#### Result -After compiling you should get these results. -```Ruby -[70, 60] -Array -``` - -## mrb_ary_pop -```C -mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); -``` -Pops the last element from the array. -#### Example -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. Now here in the Ruby files we add another method -called pop_ary that will return the array alone(just to be clean) and you should see the last element gone. -```C -#include -#include -#include "mruby/array.h" // Needs the array header. -#include "mruby/compile.h" - -int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60. - mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results. - fclose(fp); - mrb_close(mrb); - return 0; -} -``` -test.rb -```Ruby -class Example_Class - def method_name(a) - puts a - puts a.class - end - def pop_ary(a) - puts a - end -end -Example_Class.new -``` -#### Result -After compiling you should get these results. -```Ruby -[70, 60] -Array -[70] -``` -## mrb_ary_ref -```C -mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); -``` -Returns a reference to an element of the array. Specified by the value given to mrb_int n. -#### Example -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. -```C -#include -#include -#include "mruby/array.h" // Needs the array header. -#include "mruby/compile.h" - -int main(int argc, char *argv[]) -{ - mrb_value ary_ref; // Declare variable. - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1. - mrb_value obj = mrb_load_file(mrb,fp); - /* Passing the value from ary_ref to the method method_name.*/ - mrb_funcall(mrb, obj, "method_name", 1, ary_ref); - fclose(fp); - mrb_close(mrb); - return 0; -} -``` -test.rb -```Ruby -class Example_Class - def method_name(a) - puts a - puts a.class - end -end -Example_Class.new -``` -#### Result -After compiling you should get these results. -```Ruby -60 -Fixnum -``` - -### mrb_ary_set -```C -void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); -``` -Sets a value to an index. -#### Example -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. -```C -#include -#include -#include "mruby/array.h" // Needs the array header. -#include "mruby/compile.h" - -int main(int argc, char *argv[]) -{ - mrb_value new_ary; - mrb_value ary_obj; - mrb_int random_value1 = 70; - mrb_int random_value2 = 60; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - /* Sets the fixnum value of 7 to the second index of the array.*/ - mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "before_after", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; -} -``` -test.rb -```Ruby -class Example_Class - def method_name(a) - puts a - puts a.class - end - def before_after(a) - puts a - end -end -Example_Class.new -``` -#### Result -After compiling you should get these results. -```Ruby -[70, 60, 7] -``` diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md new file mode 100644 index 000000000..e1fb0003d --- /dev/null +++ b/doc/api/mruby/array.h.md @@ -0,0 +1,251 @@ +### mrb_ary_new + +```C +mrb_value mrb_ary_new(mrb_state *mrb); +``` +Initializes an array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we are declaring a variable new_ary of data type mrb_value. Then we are initializing it with the mrb_ary_new function which only takes an mruby state as an argument. +```C +#include +#include +#include "mruby/array.h" // Needs the array header. +#include "mruby/compile.h" + + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +### mrb_ary_push +```C +void mrb_ary_push(mrb_state*, mrb_value, mrb_value); +``` +Pushes given value into an array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. +```C +#include +#include +#include "mruby/array.h" // Needs the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60] +Array +``` + +## mrb_ary_pop +```C +mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); +``` +Pops the last element from the array. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case after initializing our array. We are declaring two variables with the mrb_int data type random_value1 & random_value2 and we initialize them 70 and 60 respectively. Then we use the mrb_ary_push function to push values those values into the array. Now here in the Ruby files we add another method +called pop_ary that will return the array alone(just to be clean) and you should see the last element gone. +```C +#include +#include +#include "mruby/array.h" // Needs the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60. + mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results. + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end + def pop_ary(a) + puts a + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60] +Array +[70] +``` +## mrb_ary_ref +```C +mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); +``` +Returns a reference to an element of the array. Specified by the value given to mrb_int n. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. +```C +#include +#include +#include "mruby/array.h" // Needs the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value ary_ref; // Declare variable. + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1. + mrb_value obj = mrb_load_file(mrb,fp); + /* Passing the value from ary_ref to the method method_name.*/ + mrb_funcall(mrb, obj, "method_name", 1, ary_ref); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +60 +Fixnum +``` + +### mrb_ary_set +```C +void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); +``` +Sets a value to an index. +#### Example +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument and what class the passed in value is. In this case we're declaring a variable ary_ref with the data type of mrb_value. Then we assign mrb_ary_ref to it getting new_ary's value at index 1. +```C +#include +#include +#include "mruby/array.h" // Needs the array header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_value new_ary; + mrb_value ary_obj; + mrb_int random_value1 = 70; + mrb_int random_value2 = 60; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + /* Sets the fixnum value of 7 to the second index of the array.*/ + mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "before_after", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` +test.rb +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end + def before_after(a) + puts a + end +end +Example_Class.new +``` +#### Result +After compiling you should get these results. +```Ruby +[70, 60, 7] +``` diff --git a/doc/api/mruby/value.h.md b/doc/api/mruby/value.h.md new file mode 100644 index 000000000..f3ae2d421 --- /dev/null +++ b/doc/api/mruby/value.h.md @@ -0,0 +1,238 @@ +### mrb_float_value +```C +static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) +``` + +Returns a float in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively +double i = 0.09 could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" +#include "mruby/string.h" + +int +main(void) +{ + mrb_float f = 0.09;// or double i = 0.09; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); + fclose(fp); + mrb_close(mrb); + return 0; +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + +### mrb_fixnum_value + +```C +static inline mrb_value mrb_fixnum_value(mrb_int i) +``` + +Returns a fixnum in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 +could also be used. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_int i = 99; // or int i = 99; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); + fclose(fp); + mrb_close(mrb); + return 0; +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_nil_value + +```C +static inline mrb_value mrb_nil_value(void) +``` + +Returns nil in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); + fclose(fp); + mrb_close(mrb); + return 0; +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + +### mrb_false_value + +```C +static inline mrb_value mrb_false_value(void) +``` + +Returns false in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); + fclose(fp); + mrb_close(mrb); + return 0; +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` + + + +### mrb_true_value + +```C +static inline mrb_value mrb_true_value(void) +``` + +Returns true in Ruby. + +##### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. + + +example.c +```C +#include +#include +#include "mruby/compile.h" + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); + fclose(fp); + mrb_close(mrb); + return 0; +} + +``` + +test.rb +```Ruby +class My_Class + def method_name(s) + puts s + puts s.class + end +end +a = My_Class.new +``` diff --git a/doc/api/value.h.md b/doc/api/value.h.md deleted file mode 100644 index f3ae2d421..000000000 --- a/doc/api/value.h.md +++ /dev/null @@ -1,238 +0,0 @@ -### mrb_float_value -```C -static inline mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) -``` - -Returns a float in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_float f = 0.09. Alternatively -double i = 0.09 could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" -#include "mruby/string.h" - -int -main(void) -{ - mrb_float f = 0.09;// or double i = 0.09; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_float_value(mrb, f)); - fclose(fp); - mrb_close(mrb); - return 0; -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - -### mrb_fixnum_value - -```C -static inline mrb_value mrb_fixnum_value(mrb_int i) -``` - -Returns a fixnum in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in mrb_int i = 99. Alternativly int i = 99 -could also be used. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_int i = 99; // or int i = 99; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); - fclose(fp); - mrb_close(mrb); - return 0; -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_nil_value - -```C -static inline mrb_value mrb_nil_value(void) -``` - -Returns nil in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get NillClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_nil_value()); - fclose(fp); - mrb_close(mrb); - return 0; -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - -### mrb_false_value - -```C -static inline mrb_value mrb_false_value(void) -``` - -Returns false in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get FalseClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_false_value()); - fclose(fp); - mrb_close(mrb); - return 0; -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` - - - -### mrb_true_value - -```C -static inline mrb_value mrb_true_value(void) -``` - -Returns true in Ruby. - -##### Example - -In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. In this case we are passing in nothing and we will get TrueClass. - - -example.c -```C -#include -#include -#include "mruby/compile.h" - -int -main(void) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, mrb_true_value()); - fclose(fp); - mrb_close(mrb); - return 0; -} - -``` - -test.rb -```Ruby -class My_Class - def method_name(s) - puts s - puts s.class - end -end -a = My_Class.new -``` -- cgit v1.2.3 From 449ec101f61a912f3b4b45e7378a18be784401a5 Mon Sep 17 00:00:00 2001 From: Thiago Scalone Date: Fri, 26 Jun 2015 14:22:09 -0300 Subject: Add —-recursive option to automatically update submodules from git mgems. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tasks/mruby_build_gem.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index d9d2575bd..27d4f8886 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -91,6 +91,7 @@ module MRuby end else options = [params[:options]] || [] + options << "--recursive" options << "--branch \"#{branch}\"" options << "--depth 1" unless params[:checksum_hash] FileUtils.mkdir_p "#{gem_clone_dir}" -- cgit v1.2.3 From fa4b88b89316380750a3621261bf2909d15d3c3f Mon Sep 17 00:00:00 2001 From: Thiago Scalone Date: Fri, 26 Jun 2015 14:35:34 -0300 Subject: Fix quotes use during load special path gem of gem. --- tasks/mruby_build_gem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index d9d2575bd..68de28761 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -71,7 +71,7 @@ module MRuby fail "unknown mgem protocol: #{conf['protocol']}" if conf['protocol'] != 'git' params[:git] = conf['repository'] - params[:branch] = conf['branch"] if conf["branch'] + params[:branch] = conf['branch'] if conf['branch'] end if params[:core] -- cgit v1.2.3 From c69d1201e1be22f28453dae212ba64346e02c0e2 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Sat, 27 Jun 2015 23:58:43 +0900 Subject: Fix typo; Replace extensional with extended --- mrbgems/default.gembox | 20 ++++++++++---------- mrbgems/mruby-array-ext/mrbgem.rake | 2 +- mrbgems/mruby-enum-ext/mrbgem.rake | 2 +- mrbgems/mruby-hash-ext/mrbgem.rake | 2 +- mrbgems/mruby-kernel-ext/mrbgem.rake | 2 +- mrbgems/mruby-numeric-ext/mrbgem.rake | 2 +- mrbgems/mruby-object-ext/mrbgem.rake | 2 +- mrbgems/mruby-proc-ext/mrbgem.rake | 2 +- mrbgems/mruby-range-ext/mrbgem.rake | 2 +- mrbgems/mruby-string-ext/mrbgem.rake | 2 +- mrbgems/mruby-symbol-ext/mrbgem.rake | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 30dcc1abc..d18a49d81 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -14,34 +14,34 @@ MRuby::GemBox.new do |conf| # Use standard Struct class conf.gem :core => "mruby-struct" - # Use extensional Enumerable module + # Use extended Enumerable module conf.gem :core => "mruby-enum-ext" - # Use extensional String class + # Use extended String class conf.gem :core => "mruby-string-ext" - # Use extensional Numeric class + # Use extended Numeric class conf.gem :core => "mruby-numeric-ext" - # Use extensional Array class + # Use extended Array class conf.gem :core => "mruby-array-ext" - # Use extensional Hash class + # Use extended Hash class conf.gem :core => "mruby-hash-ext" - # Use extensional Range class + # Use extended Range class conf.gem :core => "mruby-range-ext" - # Use extensional Proc class + # Use extended Proc class conf.gem :core => "mruby-proc-ext" - # Use extensional Symbol class + # Use extended Symbol class conf.gem :core => "mruby-symbol-ext" # Use Random class conf.gem :core => "mruby-random" - # Use extensional Object class + # Use extended Object class conf.gem :core => "mruby-object-ext" # Use ObjectSpace class @@ -68,7 +68,7 @@ MRuby::GemBox.new do |conf| # Generate mruby-strip command conf.gem :core => "mruby-bin-strip" - # Use extensional Kernel module + # Use extended Kernel module conf.gem :core => "mruby-kernel-ext" # Use mruby-compiler to build other mrbgems diff --git a/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake index e4b5938c7..6d7e634fb 100644 --- a/mrbgems/mruby-array-ext/mrbgem.rake +++ b/mrbgems/mruby-array-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Array class' + spec.summary = 'extended Array class' end diff --git a/mrbgems/mruby-enum-ext/mrbgem.rake b/mrbgems/mruby-enum-ext/mrbgem.rake index 0c9d88fa2..33faad31a 100644 --- a/mrbgems/mruby-enum-ext/mrbgem.rake +++ b/mrbgems/mruby-enum-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-enum-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Enumerable module' + spec.summary = 'extended Enumerable module' end diff --git a/mrbgems/mruby-hash-ext/mrbgem.rake b/mrbgems/mruby-hash-ext/mrbgem.rake index 663de2166..dcc279125 100644 --- a/mrbgems/mruby-hash-ext/mrbgem.rake +++ b/mrbgems/mruby-hash-ext/mrbgem.rake @@ -1,7 +1,7 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Hash class' + spec.summary = 'extended Hash class' spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext' spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext' end diff --git a/mrbgems/mruby-kernel-ext/mrbgem.rake b/mrbgems/mruby-kernel-ext/mrbgem.rake index ab610c02b..a81e3aee7 100644 --- a/mrbgems/mruby-kernel-ext/mrbgem.rake +++ b/mrbgems/mruby-kernel-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-kernel-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Kernel module' + spec.summary = 'extended Kernel module' end diff --git a/mrbgems/mruby-numeric-ext/mrbgem.rake b/mrbgems/mruby-numeric-ext/mrbgem.rake index 3d8be7cd5..974848079 100644 --- a/mrbgems/mruby-numeric-ext/mrbgem.rake +++ b/mrbgems/mruby-numeric-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-numeric-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Numeric class' + spec.summary = 'extended Numeric class' end diff --git a/mrbgems/mruby-object-ext/mrbgem.rake b/mrbgems/mruby-object-ext/mrbgem.rake index 91a6e7ff1..df402d3ff 100644 --- a/mrbgems/mruby-object-ext/mrbgem.rake +++ b/mrbgems/mruby-object-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-object-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Object class' + spec.summary = 'extended Object class' end diff --git a/mrbgems/mruby-proc-ext/mrbgem.rake b/mrbgems/mruby-proc-ext/mrbgem.rake index 41d964bd9..0808d468e 100644 --- a/mrbgems/mruby-proc-ext/mrbgem.rake +++ b/mrbgems/mruby-proc-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-proc-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Proc class' + spec.summary = 'extended Proc class' end diff --git a/mrbgems/mruby-range-ext/mrbgem.rake b/mrbgems/mruby-range-ext/mrbgem.rake index bcf3de202..3c1543e6f 100644 --- a/mrbgems/mruby-range-ext/mrbgem.rake +++ b/mrbgems/mruby-range-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-range-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Range class' + spec.summary = 'extended Range class' end diff --git a/mrbgems/mruby-string-ext/mrbgem.rake b/mrbgems/mruby-string-ext/mrbgem.rake index 688589933..e2f1cd678 100644 --- a/mrbgems/mruby-string-ext/mrbgem.rake +++ b/mrbgems/mruby-string-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-string-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional String class' + spec.summary = 'extended String class' end diff --git a/mrbgems/mruby-symbol-ext/mrbgem.rake b/mrbgems/mruby-symbol-ext/mrbgem.rake index b937a0742..b188cd869 100644 --- a/mrbgems/mruby-symbol-ext/mrbgem.rake +++ b/mrbgems/mruby-symbol-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-symbol-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extensional Symbol class' + spec.summary = 'extended Symbol class' end -- cgit v1.2.3 From 4e4929bc727ea5ab4a90b8bf828ac6c1f1567ba6 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Sun, 28 Jun 2015 11:15:24 +0900 Subject: Rename extended xxxx class or module to xxxx class or module extension --- mrbgems/default.gembox | 22 +++++++++++----------- mrbgems/mruby-array-ext/mrbgem.rake | 2 +- mrbgems/mruby-enum-ext/mrbgem.rake | 2 +- mrbgems/mruby-hash-ext/mrbgem.rake | 2 +- mrbgems/mruby-kernel-ext/mrbgem.rake | 2 +- mrbgems/mruby-numeric-ext/mrbgem.rake | 2 +- mrbgems/mruby-object-ext/mrbgem.rake | 2 +- mrbgems/mruby-proc-ext/mrbgem.rake | 2 +- mrbgems/mruby-range-ext/mrbgem.rake | 2 +- mrbgems/mruby-string-ext/mrbgem.rake | 2 +- mrbgems/mruby-symbol-ext/mrbgem.rake | 2 +- mrbgems/mruby-toplevel-ext/mrbgem.rake | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index d18a49d81..0960ba979 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -14,34 +14,34 @@ MRuby::GemBox.new do |conf| # Use standard Struct class conf.gem :core => "mruby-struct" - # Use extended Enumerable module + # Use Enumerable module extension conf.gem :core => "mruby-enum-ext" - # Use extended String class + # Use String class extension conf.gem :core => "mruby-string-ext" - # Use extended Numeric class + # Use Numeric class extension conf.gem :core => "mruby-numeric-ext" - # Use extended Array class + # Use Array class extension conf.gem :core => "mruby-array-ext" - # Use extended Hash class + # Use Hash class extension conf.gem :core => "mruby-hash-ext" - # Use extended Range class + # Use Range class extension conf.gem :core => "mruby-range-ext" - # Use extended Proc class + # Use Proc class extension conf.gem :core => "mruby-proc-ext" - # Use extended Symbol class + # Use Symbol class extension conf.gem :core => "mruby-symbol-ext" # Use Random class conf.gem :core => "mruby-random" - # Use extended Object class + # Use Object class extension conf.gem :core => "mruby-object-ext" # Use ObjectSpace class @@ -56,7 +56,7 @@ MRuby::GemBox.new do |conf| # Use Enumerable::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" - # Use extended toplevel object (main) methods + # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" # Generate mirb command @@ -68,7 +68,7 @@ MRuby::GemBox.new do |conf| # Generate mruby-strip command conf.gem :core => "mruby-bin-strip" - # Use extended Kernel module + # Use Kernel module extension conf.gem :core => "mruby-kernel-ext" # Use mruby-compiler to build other mrbgems diff --git a/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake index 6d7e634fb..882caf1ab 100644 --- a/mrbgems/mruby-array-ext/mrbgem.rake +++ b/mrbgems/mruby-array-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Array class' + spec.summary = 'Array class extension' end diff --git a/mrbgems/mruby-enum-ext/mrbgem.rake b/mrbgems/mruby-enum-ext/mrbgem.rake index 33faad31a..d5816b80f 100644 --- a/mrbgems/mruby-enum-ext/mrbgem.rake +++ b/mrbgems/mruby-enum-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-enum-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Enumerable module' + spec.summary = 'Enumerable module extension' end diff --git a/mrbgems/mruby-hash-ext/mrbgem.rake b/mrbgems/mruby-hash-ext/mrbgem.rake index dcc279125..f01033a6c 100644 --- a/mrbgems/mruby-hash-ext/mrbgem.rake +++ b/mrbgems/mruby-hash-ext/mrbgem.rake @@ -1,7 +1,7 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Hash class' + spec.summary = 'Hash class extension' spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext' spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext' end diff --git a/mrbgems/mruby-kernel-ext/mrbgem.rake b/mrbgems/mruby-kernel-ext/mrbgem.rake index a81e3aee7..fcb3a83b0 100644 --- a/mrbgems/mruby-kernel-ext/mrbgem.rake +++ b/mrbgems/mruby-kernel-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-kernel-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Kernel module' + spec.summary = 'Kernel module extension' end diff --git a/mrbgems/mruby-numeric-ext/mrbgem.rake b/mrbgems/mruby-numeric-ext/mrbgem.rake index 974848079..6db7e589e 100644 --- a/mrbgems/mruby-numeric-ext/mrbgem.rake +++ b/mrbgems/mruby-numeric-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-numeric-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Numeric class' + spec.summary = 'Numeric class extension' end diff --git a/mrbgems/mruby-object-ext/mrbgem.rake b/mrbgems/mruby-object-ext/mrbgem.rake index df402d3ff..6d14b4a51 100644 --- a/mrbgems/mruby-object-ext/mrbgem.rake +++ b/mrbgems/mruby-object-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-object-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Object class' + spec.summary = 'Object class extension' end diff --git a/mrbgems/mruby-proc-ext/mrbgem.rake b/mrbgems/mruby-proc-ext/mrbgem.rake index 0808d468e..e4d15a140 100644 --- a/mrbgems/mruby-proc-ext/mrbgem.rake +++ b/mrbgems/mruby-proc-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-proc-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Proc class' + spec.summary = 'Proc class extension' end diff --git a/mrbgems/mruby-range-ext/mrbgem.rake b/mrbgems/mruby-range-ext/mrbgem.rake index 3c1543e6f..e6fa7df5f 100644 --- a/mrbgems/mruby-range-ext/mrbgem.rake +++ b/mrbgems/mruby-range-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-range-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Range class' + spec.summary = 'Range class extension' end diff --git a/mrbgems/mruby-string-ext/mrbgem.rake b/mrbgems/mruby-string-ext/mrbgem.rake index e2f1cd678..f2df5a783 100644 --- a/mrbgems/mruby-string-ext/mrbgem.rake +++ b/mrbgems/mruby-string-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-string-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended String class' + spec.summary = 'String class extension' end diff --git a/mrbgems/mruby-symbol-ext/mrbgem.rake b/mrbgems/mruby-symbol-ext/mrbgem.rake index b188cd869..4f3fa43bb 100644 --- a/mrbgems/mruby-symbol-ext/mrbgem.rake +++ b/mrbgems/mruby-symbol-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-symbol-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended Symbol class' + spec.summary = 'Symbol class extension' end diff --git a/mrbgems/mruby-toplevel-ext/mrbgem.rake b/mrbgems/mruby-toplevel-ext/mrbgem.rake index eb6951f6c..ce77e0bcf 100644 --- a/mrbgems/mruby-toplevel-ext/mrbgem.rake +++ b/mrbgems/mruby-toplevel-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-toplevel-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'extended toplevel object (main) methods' + spec.summary = 'toplevel object (main) methods extension' end -- cgit v1.2.3 From a41f5eb23fad13ce8037050b7a2331c1c7dd9e6f Mon Sep 17 00:00:00 2001 From: Jurriaan Pruis Date: Sun, 28 Jun 2015 13:30:03 +0200 Subject: Fix segfault found using afl-fuzz --- mrbgems/mruby-compiler/core/codegen.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index d2eeef203..cefde8b7b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2652,13 +2652,17 @@ loop_break(codegen_scope *s, node *tree) } loop = s->loop; - while (loop->type == LOOP_BEGIN) { + while (loop && loop->type == LOOP_BEGIN) { genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL); loop = loop->prev; } - while (loop->type == LOOP_RESCUE) { + while (loop && loop->type == LOOP_RESCUE) { loop = loop->prev; } + if (!loop) { + codegen_error(s, "unexpected break"); + } + if (loop->type == LOOP_NORMAL) { int tmp; -- cgit v1.2.3 From 52db92de53a9af1adbac9e116bd19aeecd2485c1 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Mon, 29 Jun 2015 14:39:30 +0900 Subject: Fix a crash bug when GC is ran while creating a proc with env mrb_proc_new_cfunc_with_env() allocates RProc with RProc::env as NULL then allocates REnv and sets it to RProc::env of the allocated RProc. If incremental GC is ran before "allocates REnv and sets it to RProc::env of the allocated RProc", the allocated RProc's GC status is "marked" (Black) and the allocated REnv's GC status is "unmarked" (White). The next incremental GC sweeps the allocated REnv without re-marking the allocated RProc. Because the RProc is Black and the REnv is White. We need to implement write barrier for the case. We can force to cause the above situation by the following patch: diff --git a/src/proc.c b/src/proc.c index f98998f..4f4e25c 100644 --- a/src/proc.c +++ b/src/proc.c @@ -92,6 +92,7 @@ mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const struct REnv *e; int i; + mrb_incremental_gc(mrb); p->env = e = env_new(mrb, argc); MRB_ENV_UNSHARE_STACK(e); e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); With this patch, "rake test" causes segmentation fault. --- src/proc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/proc.c b/src/proc.c index f98998f68..8a2b6bbb6 100644 --- a/src/proc.c +++ b/src/proc.c @@ -93,6 +93,7 @@ mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const int i; p->env = e = env_new(mrb, argc); + mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env); MRB_ENV_UNSHARE_STACK(e); e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); if (argv) { -- cgit v1.2.3 From d6865a9cc76c67b39bb29def7a62f9b9f752363c Mon Sep 17 00:00:00 2001 From: Simon Génier Date: Mon, 29 Jun 2015 13:37:16 -0400 Subject: Avoid a narrowing cast in flo_round under MRB_INT64. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 013273232..b9aef51d9 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -436,7 +436,7 @@ flo_round(mrb_state *mrb, mrb_value num) { double number, f; mrb_int ndigits = 0; - int i; + mrb_int i; mrb_get_args(mrb, "|i", &ndigits); number = mrb_float(num); @@ -451,7 +451,7 @@ flo_round(mrb_state *mrb, mrb_value num) } f = 1.0; - i = abs(ndigits); + i = ndigits >= 0 ? ndigits : -ndigits; while (--i >= 0) f = f*10.0; -- cgit v1.2.3 From a4f63caa7947c049ad310e9e5016404b377ebe6e Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 2 Jul 2015 20:47:22 +0200 Subject: Fix incorrect memory allocation of mrdb_state_new. As detected in a Coverity scan. https://scan8.coverity.com/reports.htm#v26153/p11375/fileInstanceId=6844472&defectInstanceId=2516000&mergedDefectId=75866 --- mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index da235fad8..3e43fdb4a 100755 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -222,9 +222,9 @@ mrb_debug_context_free(mrb_state *mrb) static mrdb_state* mrdb_state_new(mrb_state *mrb) { - mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrb_state)); + mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrdb_state)); - memset(mrdb, 0, sizeof(mrb_state)); + memset(mrdb, 0, sizeof(mrdb_state)); mrdb->dbg = mrb_debug_context_get(mrb); mrdb->command = mrb_malloc(mrb, MAX_COMMAND_LINE+1); -- cgit v1.2.3 From 6a74b8bf0dd55441b87077f97e90ba29252edc53 Mon Sep 17 00:00:00 2001 From: cremno Date: Thu, 2 Jul 2015 22:11:21 +0200 Subject: add missing fall through comments --- mrbgems/mruby-compiler/core/parse.y | 2 ++ mrbgems/mruby-string-utf8/src/string.c | 1 + 2 files changed, 3 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6a43d32b..64f0a8821 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4802,6 +4802,7 @@ parser_yylex(parser_state *p) case ')': case ']': p->paren_nest--; + /* fall through */ case '}': COND_LEXPOP(); CMDARG_LEXPOP(); @@ -5133,6 +5134,7 @@ parser_yylex(parser_state *p) pushback(p, c); return '$'; } + /* fall through */ case '0': tokadd(p, '$'); } diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c index e21101df9..25a638ea3 100644 --- a/mrbgems/mruby-string-utf8/src/string.c +++ b/mrbgems/mruby-string-utf8/src/string.c @@ -259,6 +259,7 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) switch (mrb_type(indx)) { case MRB_TT_FLOAT: indx = mrb_flo_to_fixnum(mrb, indx); + /* fall through */ case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); -- cgit v1.2.3 From 43df1d7e3937162dd406dafeab79cd54dea13762 Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 3 Jul 2015 01:14:06 +0200 Subject: remove unnecessary default case --- src/dump.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dump.c b/src/dump.c index d9410ec18..2f2e5edcb 100644 --- a/src/dump.c +++ b/src/dump.c @@ -819,7 +819,6 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 uint32_t offset; switch (flags & DUMP_ENDIAN_NAT) { - default: endian_big: case DUMP_ENDIAN_BIG: memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); -- cgit v1.2.3 From 24583a7a1806dd1845700e12e8b0b823688e9879 Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 3 Jul 2015 01:30:54 +0200 Subject: fix oob write by actually truncating buffer Found by Coverity scan of polyfox-moon: CID 121927 (#1 of 1): Out-of-bounds write (OVERRUN) --- mrbgems/mruby-compiler/core/parse.y | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6a43d32b..26062967d 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3604,10 +3604,13 @@ toklast(parser_state *p) static void tokfix(parser_state *p) { - if (p->bidx >= MRB_PARSER_BUF_SIZE) { + int i = p->bidx, imax = MRB_PARSER_BUF_SIZE - 1; + + if (i > imax) { + i = imax; yyerror(p, "string too long (truncated)"); } - p->buf[p->bidx] = '\0'; + p->buf[i] = '\0'; } static const char* -- cgit v1.2.3 From 7206a8c4f91bd54390b6e244d6a32f9766b8e05f Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 3 Jul 2015 02:48:22 +0200 Subject: fix dangling pointer CID 75872 (#3-2 of 3): Pointer to local outside scope (RETURN_LOCAL) 38. use_invalid: Using p, which points to an out-of-scope variable buf. --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 8df79d4c0..757317bdc 100644 --- a/src/string.c +++ b/src/string.c @@ -2057,6 +2057,7 @@ MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) { char *end; + char buf[DBL_DIG * 4 + 10]; double d; enum {max_width = 20}; @@ -2077,7 +2078,6 @@ bad: return d; } if (*end) { - char buf[DBL_DIG * 4 + 10]; char *n = buf; char *e = buf + sizeof(buf) - 1; char prev = 0; -- cgit v1.2.3 From 03ae38df4e18c33e6ce4f5614bd4ec7b1ba9f192 Mon Sep 17 00:00:00 2001 From: Anton Davydov Date: Sun, 5 Jul 2015 13:49:37 +0300 Subject: Fix typo in comment in String#mrb_cstr_to_inum [skip ci] --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 8df79d4c0..57b5eef9a 100644 --- a/src/string.c +++ b/src/string.c @@ -1927,7 +1927,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) } break; } /* end of switch (base) { */ - if (*str == '0') { /* squeeze preceeding 0s */ + if (*str == '0') { /* squeeze preceding 0s */ uscore = 0; while ((c = *++str) == '0' || c == '_') { if (c == '_') { -- cgit v1.2.3 From 0b50b4a5005c3233b88b09f196034352ebdfc515 Mon Sep 17 00:00:00 2001 From: xuejianqing Date: Mon, 6 Jul 2015 12:51:57 +0800 Subject: fix androideabi cross-compile error : undefined reference to 'frexpl' --- src/fmt_fp.c | 9 +++------ tasks/toolchains/androideabi.rake | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index a634edb34..b467435a3 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -90,12 +90,9 @@ fmt_u(uint32_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -#if (defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__) -static long double -frexpl (long double x, int *eptr) -{ - return frexp(x, eptr); -} +#if ((defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) +#undef frexpl +#define frexpl frexp #endif static int diff --git a/tasks/toolchains/androideabi.rake b/tasks/toolchains/androideabi.rake index 61881ca31..7cdb9e43a 100644 --- a/tasks/toolchains/androideabi.rake +++ b/tasks/toolchains/androideabi.rake @@ -109,8 +109,8 @@ MRuby::Toolchain.new(:androideabi) do |conf| ANDROID_CC = path_to_toolchain + '/bin/' + toolchain_prefix + 'gcc' ANDROID_LD = path_to_toolchain + '/bin/' + toolchain_prefix + 'gcc' ANDROID_AR = path_to_toolchain + '/bin/' + toolchain_prefix + 'ar' - ANDROID_CFLAGS = GCC_COMMON_CFLAGS + %W(-mandroid --sysroot="#{SYSROOT}") + ARCH_CFLAGS - ANDROID_LDFLAGS = GCC_COMMON_LDFLAGS + %W(-mandroid --sysroot="#{SYSROOT}") + ARCH_LDFLAGS + ANDROID_CFLAGS = GCC_COMMON_CFLAGS + %W(-D__android__ -mandroid --sysroot="#{SYSROOT}") + ARCH_CFLAGS + ANDROID_LDFLAGS = GCC_COMMON_LDFLAGS + %W(-D__android__ -mandroid --sysroot="#{SYSROOT}") + ARCH_LDFLAGS when 'clang' then # clang is not supported yet. when 'clang31', 'clang3.1' then -- cgit v1.2.3 From 40252169fc9762f222106f116f2bcc510b038bf9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 7 Jul 2015 10:32:37 +0900 Subject: method_missing definition may be undefined; fix #2878 --- src/vm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 1f3b05df2..15a3926e3 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1074,9 +1074,14 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_no_method_error(mrb, mid, n, regs+a+1, + "undefined method '%S' for %S", mrb_sym2str(mrb, mid), recv); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } -- cgit v1.2.3 From 2523ed473af8d9e97c641f7263286d1af40a69a3 Mon Sep 17 00:00:00 2001 From: Mav7 Date: Wed, 8 Jul 2015 04:50:01 -0400 Subject: Added new markdowns. --- doc/api/mruby/hash.h.md | 0 doc/api/mruby/range.h.md | 0 doc/api/mruby/string.h.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/mruby/hash.h.md create mode 100644 doc/api/mruby/range.h.md create mode 100644 doc/api/mruby/string.h.md diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md new file mode 100644 index 000000000..e69de29bb diff --git a/doc/api/mruby/range.h.md b/doc/api/mruby/range.h.md new file mode 100644 index 000000000..e69de29bb diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 82380780db07e9d776d3d7983a229a114f30ecb8 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Wed, 8 Jul 2015 05:35:37 -0400 Subject: Update hash.h.md --- doc/api/mruby/hash.h.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md index e69de29bb..1d713d59e 100644 --- a/doc/api/mruby/hash.h.md +++ b/doc/api/mruby/hash.h.md @@ -0,0 +1,96 @@ +### mrb_hash_new + +```C +mrb_value mrb_hash_new(mrb_state *mrb); +``` + +Initializes a hash. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example initializes a hash. In pure Ruby doing this is equivalent +to Hash.new. + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +``` Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +### mrb_hash_set + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable. + mrb_sym hash_key = mrb_intern_cstr(mrb, "da_key"); // Declare a symbol. + mrb_int hash_value = 80; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key), mrb_fixnum_value(hash_value)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +#### Result + +After compiling you should get these results. + +```Ruby +{:da_key=>80} +Hash +``` + + -- cgit v1.2.3 From 1167fd1ae440aa2b2b3d2cee5cb5a266d83f46e8 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 8 Jul 2015 18:25:52 +0900 Subject: use round for llround. some platform (ex: mingw32) doesn't have llround. --- mrbgems/mruby-time/src/time.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 081e84c1c..c18ac7568 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -11,6 +11,10 @@ #include "mruby/class.h" #include "mruby/data.h" +#if !defined(__MINGW64__) && defined(_WIN32) +# define llround(x) round(x) +#endif + #if defined(__MINGW64__) || defined(__MINGW32__) # include #endif -- cgit v1.2.3 From bdbd696c486f88a2239420a027f7e1772713bbe0 Mon Sep 17 00:00:00 2001 From: jbreeden Date: Sat, 11 Jul 2015 21:03:04 -0700 Subject: Patching array join --- src/array.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/array.c b/src/array.c index f48719310..ff0bb8a85 100644 --- a/src/array.c +++ b/src/array.c @@ -295,7 +295,7 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "a", &ptr, &blen); if (ARY_MAX_SIZE - blen < a1->len) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } a2 = ary_new_capa(mrb, a1->len + blen); array_copy(a2->ptr, a1->ptr, a1->len); @@ -349,7 +349,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) } if (times == 0) return mrb_ary_new(mrb); if (ARY_MAX_SIZE / times < a1->len) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } a2 = ary_new_capa(mrb, a1->len * times); ptr = a2->ptr; @@ -1031,7 +1031,13 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary) { mrb_value sep = mrb_nil_value(); - mrb_get_args(mrb, "|S", &sep); + mrb_get_args(mrb, "|o", &sep); + if (mrb_nil_p(sep)) { + sep = mrb_str_to_str(mrb, sep); + } else if (mrb_type(sep) != MRB_TT_STRING) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + return mrb_nil_value(); + } return mrb_ary_join(mrb, ary, sep); } -- cgit v1.2.3 From dd558a108d20d2198cb52cf743e2ecfc868cfa1c Mon Sep 17 00:00:00 2001 From: jbreeden Date: Sat, 11 Jul 2015 21:15:33 -0700 Subject: Removing unndeeded to_s --- src/array.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/array.c b/src/array.c index ff0bb8a85..2fb662c92 100644 --- a/src/array.c +++ b/src/array.c @@ -1032,9 +1032,7 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary) mrb_value sep = mrb_nil_value(); mrb_get_args(mrb, "|o", &sep); - if (mrb_nil_p(sep)) { - sep = mrb_str_to_str(mrb, sep); - } else if (mrb_type(sep) != MRB_TT_STRING) { + if (!(mrb_nil_p(sep) || mrb_type(sep) == MRB_TT_STRING)) { mrb_raise(mrb, E_TYPE_ERROR, "expected String"); return mrb_nil_value(); } -- cgit v1.2.3 From 9c311ddc938ad2cc88e4119374e47cd496e15a94 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Jul 2015 07:08:01 +0900 Subject: refactor mrb_bob_missing to share raising NoMethodError code; fix #2878 Note: arguments of mrb_no_method_error() has changed. You need to replace 3rd and 4th argument (say n, argv) to mrb_ary_new_from_values(mrb, n, argv). --- include/mruby/error.h | 2 +- src/class.c | 45 ++++++++++++++++++++++++++------------------- src/error.c | 5 ++--- src/vm.c | 13 +++++++++++-- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/include/mruby/error.h b/include/mruby/error.h index 52f6772bd..282be0a24 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -24,7 +24,7 @@ MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value st MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb); -MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...); /* declaration for fail method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); diff --git a/src/class.c b/src/class.c index e9cbc592d..0f9a77b2a 100644 --- a/src/class.c +++ b/src/class.c @@ -1262,6 +1262,31 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv) return mrb_bool_value(!mrb_test(cv)); } +void +mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) +{ + mrb_sym inspect; + mrb_value repr; + + inspect = mrb_intern_lit(mrb, "inspect"); + if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { + /* method missing in inspect; avoid recursion */ + repr = mrb_any_to_s(mrb, self); + } + else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { + repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, self); + } + } + else { + repr = mrb_any_to_s(mrb, self); + } + + mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", + mrb_sym2str(mrb, name), repr); +} + /* 15.3.1.3.30 */ /* * call-seq: @@ -1301,27 +1326,9 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod) mrb_sym name; mrb_value *a; mrb_int alen; - mrb_sym inspect; - mrb_value repr; mrb_get_args(mrb, "n*", &name, &a, &alen); - - inspect = mrb_intern_lit(mrb, "inspect"); - if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { - /* method missing in inspect; avoid recursion */ - repr = mrb_any_to_s(mrb, mod); - } - else if (mrb_respond_to(mrb, mod, inspect) && mrb->c->ci - mrb->c->cibase < 64) { - repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0); - if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { - repr = mrb_any_to_s(mrb, mod); - } - } - else { - repr = mrb_any_to_s(mrb, mod); - } - - mrb_no_method_error(mrb, name, alen, a, "undefined method '%S' for %S", mrb_sym2str(mrb, name), repr); + mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); /* not reached */ return mrb_nil_value(); } diff --git a/src/error.c b/src/error.c index a800f77f9..20c63bd43 100644 --- a/src/error.c +++ b/src/error.c @@ -424,15 +424,14 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) } MRB_API mrb_noreturn void -mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...) +mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...) { mrb_value exc; va_list ap; va_start(ap, fmt); exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3, - mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), - mrb_ary_new_from_values(mrb, argc, argv)); + mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), args); va_end(ap); mrb_exc_raise(mrb, exc); } diff --git a/src/vm.c b/src/vm.c index 15a3926e3..22ea177e0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -723,6 +723,8 @@ argnum_error(mrb_state *mrb, mrb_int num) #define CALL_MAXARGS 127 +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + MRB_API mrb_value mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { @@ -1078,8 +1080,15 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, missing); if (!m) { - mrb_no_method_error(mrb, mid, n, regs+a+1, - "undefined method '%S' for %S", mrb_sym2str(mrb, mid), recv); + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); } mid = missing; if (n == CALL_MAXARGS) { -- cgit v1.2.3 From 02474daa14623f3ee24a5235e9b7b88c33d43455 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Jul 2015 11:14:50 +0900 Subject: allow '!' after 'S' specifier of mrb_get_args() that allow nil. thus "S!" means String|nil type. you have to check nil before dereferencing the value. this is added to address #2882 while keeping code simplicity. besides that current #2882 fix lose polymorphism provided by mrb_get_args(). --- src/class.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 0f9a77b2a..8a9fdaca6 100644 --- a/src/class.c +++ b/src/class.c @@ -435,7 +435,7 @@ to_sym(mrb_state *mrb, mrb_value ss) ---------------------------------------------------------------------------------------------- o: Object [mrb_value] C: class/module [mrb_value] - S: String [mrb_value] + S: String [mrb_value] when ! follows the value may be nil A: Array [mrb_value] H: Hash [mrb_value] s: String [char*,mrb_int] Receive two arguments. @@ -525,6 +525,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_str(mrb, *sp++); i++; -- cgit v1.2.3 From d0e67aada795620c2bce49db8c73e87718753614 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Jul 2015 11:18:44 +0900 Subject: use "S!" specifier of mrb_get_args() to improve #2882 fix. --- src/array.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/array.c b/src/array.c index 2fb662c92..0a99040c0 100644 --- a/src/array.c +++ b/src/array.c @@ -1031,11 +1031,7 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary) { mrb_value sep = mrb_nil_value(); - mrb_get_args(mrb, "|o", &sep); - if (!(mrb_nil_p(sep) || mrb_type(sep) == MRB_TT_STRING)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - return mrb_nil_value(); - } + mrb_get_args(mrb, "|S!", &sep); return mrb_ary_join(mrb, ary, sep); } -- cgit v1.2.3 From f962890a928b566c0f5ca7fdff5ef4ce19207e65 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 9 Jul 2015 23:46:54 +0200 Subject: Implement Module#prepend. --- include/mruby/class.h | 1 + src/class.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-- test/t/module.rb | 33 +++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 9d5260a24..60310ae9d 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -16,6 +16,7 @@ struct RClass { struct iv_tbl *iv; struct kh_mt *mt; struct RClass *super; + struct RClass *origin; }; #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) diff --git a/src/class.c b/src/class.c index 8a9fdaca6..3b1ea2321 100644 --- a/src/class.c +++ b/src/class.c @@ -194,6 +194,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); + c = c->origin; if (super && mrb_class_real(c->super) != super) { mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", mrb_sym2str(mrb, name), @@ -763,12 +764,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super) else { c->super = mrb->object_class; } + c->origin = c; c->mt = kh_init(mt, mrb); return c; } -MRB_API void -mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +MRB_API inline void +include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *m, int search_super) { struct RClass *ins_pos; @@ -782,6 +784,7 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) } while (p) { if (c != p && p->tt == MRB_TT_CLASS) { + if (!search_super) break; superclass_seen = 1; } else if (p->mt == m->mt) { @@ -810,6 +813,63 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) } } +MRB_API void +mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + include_module_at(mrb, c, m, FALSE); +} + +MRB_API void +mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + struct RClass *origin; + int changed = 0; + + origin = c->origin; + if (origin == c) { + origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); + //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */ + origin->super = c->super; + c->super = origin; + c->origin = origin; + origin->mt = c->mt; + c->mt = kh_init(mt, mrb); + } + include_module_at(mrb, c, m, FALSE); // changed = + if (changed) { + //rb_vm_check_redefinition_by_prepend(klass); + } +} + +static mrb_value +mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod) +{ + mrb_value klass; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_get_args(mrb, "C", &klass); + mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + return mod; +} + +static mrb_value +mrb_mod_prepend(mrb_state *mrb, mrb_value klass) +{ + mrb_value *argv; + mrb_int argc, i; + + mrb_get_args(mrb, "*", &argv, &argc); + for (i=0; i Date: Fri, 10 Jul 2015 20:17:16 +0200 Subject: Rename classes because of conflicts --- test/t/module.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 9faaf6e2c..3c87c122b 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -491,18 +491,18 @@ assert('Module#prepend') do def m1; [:M4, super, :M4] end end - class C0 + class P0 include M0 prepend M1 def m1; [:C0, super, :C0] end end - class C1 < C0 + class P1 < P0 prepend M2, M3 include M4 def m1; [:C1, super, :C1] end end - obj = C1.new + obj = P1.new expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2] assert_equal(expected, obj.m1) end -- cgit v1.2.3 From ad9f32c5a876d5f230584b3c9abe77833943e6e6 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 10 Jul 2015 21:00:14 +0200 Subject: Expose insert position, which should be at origin for include and klass for prepend. --- src/class.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/class.c b/src/class.c index 3b1ea2321..c1d377e86 100644 --- a/src/class.c +++ b/src/class.c @@ -770,11 +770,8 @@ boot_defclass(mrb_state *mrb, struct RClass *super) } MRB_API inline void -include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *m, int search_super) +include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) { - struct RClass *ins_pos; - - ins_pos = c; while (m) { struct RClass *p = c, *ic; int superclass_seen = 0; @@ -816,7 +813,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *m, int search MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - include_module_at(mrb, c, m, FALSE); + include_module_at(mrb, c, c->origin, m, FALSE); } MRB_API void @@ -835,7 +832,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) origin->mt = c->mt; c->mt = kh_init(mt, mrb); } - include_module_at(mrb, c, m, FALSE); // changed = + include_module_at(mrb, c, c, m, FALSE); // changed = if (changed) { //rb_vm_check_redefinition_by_prepend(klass); } -- cgit v1.2.3 From 2e617e37e134b428ce7a979446cc2d768d1cf2fe Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 10 Jul 2015 21:14:28 +0200 Subject: origin must be initialized --- src/class.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class.c b/src/class.c index c1d377e86..9f21ae395 100644 --- a/src/class.c +++ b/src/class.c @@ -76,6 +76,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); + sc->origin = sc; sc->mt = 0; sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -799,6 +800,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru else { ic->c = m; } + ic->origin = ic; ic->mt = m->mt; ic->iv = m->iv; ic->super = ins_pos->super; @@ -825,6 +827,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) origin = c->origin; if (origin == c) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); + origin->origin = origin; //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */ origin->super = c->super; c->super = origin; @@ -1547,6 +1550,7 @@ MRB_API struct RClass* mrb_module_new(mrb_state *mrb) { struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); + m->origin = m; m->mt = kh_init(mt, mrb); return m; -- cgit v1.2.3 From 97529c2a9a7b75a838234a420bbe2c6dc59c56ba Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 10 Jul 2015 22:01:07 +0200 Subject: Comment in a refactor to match MRI, but that fails 320 tests. --- src/class.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 9f21ae395..ca4582041 100644 --- a/src/class.c +++ b/src/class.c @@ -776,11 +776,25 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru while (m) { struct RClass *p = c, *ic; int superclass_seen = 0; - + + //if (m->origin != m) + // goto skip; if (c->mt && c->mt == m->mt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } while (p) { + /*if (p->tt == MRB_TT_ICLASS) { + if (!superclass_seen) { + ins_pos = p; // move insert point + } + goto skip; + } else if (p->tt == MRB_TT_CLASS) { + if (p->mt == m->mt) { + if (!search_super) break; + superclass_seen = 1; + } + }*/ + // if (c != p && p->tt == MRB_TT_CLASS) { if (!search_super) break; superclass_seen = 1; -- cgit v1.2.3 From 005cacf18b8ce2cf854872aa8cb803819478a47d Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:15:18 +0200 Subject: Additional patches to make this work --- src/class.c | 129 ++++++++++++++++++++++++++++++++--------------------------- src/kernel.c | 12 ++++++ 2 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/class.c b/src/class.c index ca4582041..73e6687c0 100644 --- a/src/class.c +++ b/src/class.c @@ -325,9 +325,16 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s MRB_API void mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) { - khash_t(mt) *h = c->mt; + khash_t(mt) *h; khiter_t k; + if (!c->origin) { + printf("Warning, class %s does not have valid origin\n", mrb_class_name(mrb, c)); + mrb_raisef(mrb, E_RUNTIME_ERROR, "Invalid origin"); + c->origin = c; + } + h = c->origin->mt; + if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = p; @@ -758,6 +765,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super) struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); + c->origin = c; if (super) { c->super = super; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); @@ -765,71 +773,74 @@ boot_defclass(mrb_state *mrb, struct RClass *super) else { c->super = mrb->object_class; } - c->origin = c; c->mt = kh_init(mt, mrb); return c; } -MRB_API inline void -include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) +static struct RClass* +include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) +{ + struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); + if (m->tt == MRB_TT_ICLASS) { + m = m->c; + } + ic->origin = ic; + ic->iv = m->iv; + ic->mt = m->origin->mt; + ic->super = super; + if (m->tt == MRB_TT_ICLASS) { + ic->c = m->c; + } else { + ic->c = m; + } + return ic; +} + +MRB_API int +include_module_at(mrb_state *mrb, struct RClass *klass, struct RClass *c, struct RClass *module, int search_super) { - while (m) { - struct RClass *p = c, *ic; + struct RClass *p, *iclass; + void *klass_mt = klass->origin->mt; + + while (module) { int superclass_seen = 0; - - //if (m->origin != m) - // goto skip; - if (c->mt && c->mt == m->mt) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); - } - while (p) { - /*if (p->tt == MRB_TT_ICLASS) { - if (!superclass_seen) { - ins_pos = p; // move insert point + + if (module->origin != module) + goto skip; + + if (klass_mt && klass_mt == module->mt) + return -1; + + p = klass->super; + while(p) { + if (p->tt == MRB_TT_ICLASS) { + if (p->mt == module->mt) { + if (!superclass_seen) { + c = p; // move insert point + } + goto skip; } - goto skip; } else if (p->tt == MRB_TT_CLASS) { - if (p->mt == m->mt) { - if (!search_super) break; - superclass_seen = 1; - } - }*/ - // - if (c != p && p->tt == MRB_TT_CLASS) { if (!search_super) break; superclass_seen = 1; } - else if (p->mt == m->mt) { - if (p->tt == MRB_TT_ICLASS && !superclass_seen) { - ins_pos = p; - } - goto skip; - } p = p->super; } - ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); - if (m->tt == MRB_TT_ICLASS) { - ic->c = m->c; - } - else { - ic->c = m; - } - ic->origin = ic; - ic->mt = m->mt; - ic->iv = m->iv; - ic->super = ins_pos->super; - ins_pos->super = ic; - mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); - ins_pos = ic; + + iclass = include_class_new(mrb, module, c->super); + c->super = iclass; + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->super); + c = iclass; skip: - m = m->super; + module = module->super; } + return 0; } MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - include_module_at(mrb, c, c->origin, m, FALSE); + include_module_at(mrb, c, c->origin, m, 1); } MRB_API void @@ -842,16 +853,16 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) if (origin == c) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->origin = origin; - //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */ origin->super = c->super; c->super = origin; c->origin = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->origin); } - include_module_at(mrb, c, c, m, FALSE); // changed = - if (changed) { - //rb_vm_check_redefinition_by_prepend(klass); + changed = include_module_at(mrb, c, c, m, 0); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected"); } } @@ -955,15 +966,12 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); - result = mrb_ary_new(mrb); - mrb_ary_push(mrb, result, mrb_obj_value(c)); - c = c->super; while (c) { if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (c->tt != MRB_TT_SCLASS) { + else if (c->origin == c) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1005,9 +1013,14 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; + /* hack, fix missing module->origin */ + struct RClass *m = mrb_class_ptr(mod); + if (!m->origin) + m->origin = m; + mrb_get_args(mrb, "&", &b); if (!mrb_nil_p(b)) { - mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod)); + mrb_yield_with_class(mrb, b, 1, &mod, mod, m); } return mod; } @@ -1324,9 +1337,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->super; + c = c->origin->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->super; + c = c->origin->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1925,7 +1938,7 @@ static void remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) { struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = c->mt; + khash_t(mt) *h = c->origin->mt; khiter_t k; if (h) { diff --git a/src/kernel.c b/src/kernel.c index b5b13f874..bafab6e76 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -248,6 +248,11 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); } + if (klass->origin != klass) + clone->origin = klass->origin; + else + clone->origin = clone; + clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -269,6 +274,13 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) { struct RClass *dc = mrb_class_ptr(dst); struct RClass *sc = mrb_class_ptr(src); + /* if the origin is not the same as the class, then the origin and + the current class need to be copied */ + if (sc->origin != sc) { + dc->origin = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(sc->origin))); + } else { + dc->origin = dc; + } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; } -- cgit v1.2.3 From ce6672717706365929b1c2c3c2c278e75a3c4be4 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 08:16:04 -0500 Subject: Remove some remnant debug code --- src/class.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/class.c b/src/class.c index 73e6687c0..e9df1dae4 100644 --- a/src/class.c +++ b/src/class.c @@ -327,12 +327,6 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro { khash_t(mt) *h; khiter_t k; - - if (!c->origin) { - printf("Warning, class %s does not have valid origin\n", mrb_class_name(mrb, c)); - mrb_raisef(mrb, E_RUNTIME_ERROR, "Invalid origin"); - c->origin = c; - } h = c->origin->mt; if (!h) h = c->mt = kh_init(mt, mrb); -- cgit v1.2.3 From 40f48034d512a8e4f24f8d67373f18093e96513c Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 08:25:43 -0500 Subject: Added changed check to the mrb_include_module --- src/class.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index e9df1dae4..4a64e5b23 100644 --- a/src/class.c +++ b/src/class.c @@ -834,7 +834,10 @@ include_module_at(mrb_state *mrb, struct RClass *klass, struct RClass *c, struct MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - include_module_at(mrb, c, c->origin, m, 1); + int changed = include_module_at(mrb, c, c->origin, m, 1); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); + } } MRB_API void -- cgit v1.2.3 From d4b009b394d3933ee1b828d0e91d3c6aaa522339 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:09:13 -0500 Subject: Fixed Modules not being fully initialized before #initialize was called --- src/class.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/class.c b/src/class.c index 4a64e5b23..d83216cb4 100644 --- a/src/class.c +++ b/src/class.c @@ -77,7 +77,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); sc->origin = sc; - sc->mt = 0; + sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { c = (struct RClass*)o; @@ -771,6 +771,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super) return c; } +static void +boot_initmod(mrb_state *mrb, struct RClass *mod) +{ + mod->origin = mod; + mod->mt = kh_init(mt, mrb); +} + static struct RClass* include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) { @@ -1012,10 +1019,8 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) /* hack, fix missing module->origin */ struct RClass *m = mrb_class_ptr(mod); - if (!m->origin) - m->origin = m; - - mrb_get_args(mrb, "&", &b); + boot_initmod(mrb, m); // bootstrap a newly initialized module + mrb_get_args(mrb, "|&", &b); if (!mrb_nil_p(b)) { mrb_yield_with_class(mrb, b, 1, &mod, mod, m); } @@ -1574,9 +1579,7 @@ MRB_API struct RClass* mrb_module_new(mrb_state *mrb) { struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); - m->origin = m; - m->mt = kh_init(mt, mrb); - + boot_initmod(mrb, m); return m; } -- cgit v1.2.3 From 99aff17075905738a8e45d8b213b92a291588053 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:09:52 -0500 Subject: Ported a bit more of the MRI Module#prepend tests over Currently kind_of fails miserably, still looking for the reason --- test/t/module.rb | 94 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 3c87c122b..6fa22e8b4 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -474,38 +474,80 @@ end # Not ISO specified +# @!group prepend assert('Module#prepend') do - module M0 - def m1; [:M0] end - end - module M1 - def m1; [:M1, super, :M1] end - end - module M2 - def m1; [:M2, super, :M2] end - end - M3 = Module.new do - def m1; [:M3, super, :M3] end - end - module M4 - def m1; [:M4, super, :M4] end - end + assert('test_prepend') do + module M0 + def m1; [:M0] end + end + module M1 + def m1; [:M1, super, :M1] end + end + module M2 + def m1; [:M2, super, :M2] end + end + M3 = Module.new do + def m1; [:M3, super, :M3] end + end + module M4 + def m1; [:M4, super, :M4] end + end - class P0 - include M0 - prepend M1 - def m1; [:C0, super, :C0] end + class P0 + include M0 + prepend M1 + def m1; [:C0, super, :C0] end + end + class P1 < P0 + prepend M2, M3 + include M4 + def m1; [:C1, super, :C1] end + end + + obj = P1.new + expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2] + assert_equal(expected, obj.m1) end - class P1 < P0 - prepend M2, M3 - include M4 - def m1; [:C1, super, :C1] end + + # mruby shouldn't be affected by this since there is + # no visibility control (yet) + assert('test_public_prepend') do + assert_nothing_raised('ruby/ruby #8846') do + Class.new.prepend(Module.new) + end end - obj = P1.new - expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2] - assert_equal(expected, obj.m1) + assert('test_prepend_inheritance') do + bug6654 = '[ruby-core:45914]' + a = Module.new + b = Module.new { include a } + c = Module.new { prepend b } + + assert bug6654 do + # the Module#< operator should be used here instead, but we don't have it + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + end + + bug8357 = '[ruby-core:54736] [Bug #8357]' + b = Module.new { prepend a } + c = Class.new { include b } + + assert bug8357 do + # the Module#< operator should be used here instead, but we don't have it + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + end + + bug8357 = '[ruby-core:54742] [Bug #8357]' + t_print c.new.kind_of?(b) + t_print "\n" + t_print [b, b.ancestors, c, c.ancestors].inspect + t_print "\n" + assert_kind_of(b, c.new, bug8357) + end end +# @!endgroup prepend assert('Module#to_s') do module Test4to_sModules -- cgit v1.2.3 From 319553f0ef310b4f098773db713e7fcee18f69be Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:11:12 -0500 Subject: Removed some debug prints from the test --- test/t/module.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 6fa22e8b4..5baaadd2e 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -540,10 +540,6 @@ assert('Module#prepend') do end bug8357 = '[ruby-core:54742] [Bug #8357]' - t_print c.new.kind_of?(b) - t_print "\n" - t_print [b, b.ancestors, c, c.ancestors].inspect - t_print "\n" assert_kind_of(b, c.new, bug8357) end end -- cgit v1.2.3 From 47264bf2898fbfa5cae6709074b5e5564dbbe99c Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:32:20 -0500 Subject: Ported all MRI prepend tests And of course, some of them fail miserably --- test/t/module.rb | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 226 insertions(+), 5 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 5baaadd2e..7314d140f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -1,6 +1,26 @@ ## # Module ISO Test +def labeled_module(name, &block) + Module.new do + singleton_class.class_eval do + define_method(:to_s) { name } + alias_method :inspect, :to_s + end + class_eval(&block) if block + end +end + +def labeled_class(name, supklass = Object, &block) + Class.new(supklass) do + singleton_class.class_eval do + define_method(:to_s) { name } + alias_method :inspect, :to_s + end + class_eval(&block) if block + end +end + assert('Module', '15.2.2') do assert_equal Class, Module.class end @@ -519,9 +539,9 @@ assert('Module#prepend') do assert('test_prepend_inheritance') do bug6654 = '[ruby-core:45914]' - a = Module.new - b = Module.new { include a } - c = Module.new { prepend b } + a = labeled_module('a') + b = labeled_module('b') { include a } + c = labeled_module('c') { prepend b } assert bug6654 do # the Module#< operator should be used here instead, but we don't have it @@ -530,8 +550,8 @@ assert('Module#prepend') do end bug8357 = '[ruby-core:54736] [Bug #8357]' - b = Module.new { prepend a } - c = Class.new { include b } + b = labeled_module('b') { prepend a } + c = labeled_class('c') { include b } assert bug8357 do # the Module#< operator should be used here instead, but we don't have it @@ -542,6 +562,207 @@ assert('Module#prepend') do bug8357 = '[ruby-core:54742] [Bug #8357]' assert_kind_of(b, c.new, bug8357) end + + assert('test_prepend_instance_methods') do + bug6655 = '[ruby-core:45915]' + assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) + end + + assert 'test_prepend_singleton_methods' do + o = Object.new + o.singleton_class.class_eval {prepend Module.new} + assert_equal([], o.singleton_methods) + end + + assert 'test_prepend_remove_method' do + c = Class.new do + prepend Module.new { def foo; end } + end + assert_raise(NameError) do + c.class_eval do + remove_method(:foo) + end + end + c.class_eval do + def foo; end + end + removed = nil + c.singleton_class.class_eval do + define_method(:method_removed) {|id| removed = id} + end + assert_nothing_raised(NoMethodError, NameError, '[Bug #7843]') do + c.class_eval do + remove_method(:foo) + end + end + assert_equal(:foo, removed) + end + + assert 'test_prepend_class_ancestors' do + bug6658 = '[ruby-core:45919]' + m = labeled_module("m") + c = labeled_class("c") {prepend m} + assert_equal([m, c], c.ancestors[0, 2], bug6658) + + bug6662 = '[ruby-dev:45868]' + c2 = labeled_class("c2", c) + anc = c2.ancestors + assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662) + end + + # this assertion causes the mrbtest to segfault + #assert 'test_prepend_module_ancestors' do + # bug6659 = '[ruby-dev:45861]' + # m0 = labeled_module("m0") { def x; [:m0, *super] end } + # m1 = labeled_module("m1") { def x; [:m1, *super] end; prepend m0 } + # m2 = labeled_module("m2") { def x; [:m2, *super] end; prepend m1 } + # c0 = labeled_class("c0") { def x; [:c0] end } + # c1 = labeled_class("c1") { def x; [:c1] end; prepend m2 } + # c2 = labeled_class("c2", c0) { def x; [:c2, *super] end; include m2 } + # # + # assert_equal([m0, m1], m1.ancestors, bug6659) + # # + # bug6662 = '[ruby-dev:45868]' + # assert_equal([m0, m1, m2], m2.ancestors, bug6662) + # assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) + # assert_equal([:m0, :m1, :m2, :c1], c1.new.x) + # assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) + # assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x) + # # + # m3 = labeled_module("m3") { include m1; prepend m1 } + # assert_equal([m3, m0, m1], m3.ancestors) + # m3 = labeled_module("m3") { prepend m1; include m1 } + # assert_equal([m0, m1, m3], m3.ancestors) + # m3 = labeled_module("m3") { prepend m1; prepend m1 } + # assert_equal([m0, m1, m3], m3.ancestors) + # m3 = labeled_module("m3") { include m1; include m1 } + # assert_equal([m3, m0, m1], m3.ancestors) + #end + + assert 'test_prepend_instance_methods_false' do + bug6660 = '[ruby-dev:45863]' + assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + end + + assert 'test_cyclic_prepend' do + bug7841 = '[ruby-core:52205] [Bug #7841]' + m1 = Module.new + m2 = Module.new + m1.instance_eval { prepend(m2) } + assert_raise(ArgumentError, bug7841) do + m2.instance_eval { prepend(m1) } + end + end + + # these assertions will not run without a #assert_seperately method + #assert 'test_prepend_optmethod' do + # bug7983 = '[ruby-dev:47124] [Bug #7983]' + # assert_separately [], %{ + # module M + # def /(other) + # to_f / other + # end + # end + # Fixnum.send(:prepend, M) + # assert_equal(0.5, 1 / 2, "#{bug7983}") + # } + # assert_equal(0, 1 / 2) + #end + + #assert 'test_prepend_visibility' do + # bug8005 = '[ruby-core:53106] [Bug #8005]' + # c = Class.new do + # prepend Module.new {} + # def foo() end + # protected :foo + # end + # a = c.new + # assert_respond_to a, [:foo, true], bug8005 + # assert_nothing_raised(NoMethodError, bug8005) {a.send :foo} + #end + + #assert 'test_prepend_visibility_inherited' do + # bug8238 = '[ruby-core:54105] [Bug #8238]' + # assert_separately [], <<-"end;", timeout: 20 + # class A + # def foo() A; end + # private :foo + # end + # class B < A + # public :foo + # prepend Module.new + # end + # assert_equal(A, B.new.foo, "#{bug8238}") + # end; + #end + + assert 'test_prepend_included_modules' do + bug8025 = '[ruby-core:53158] [Bug #8025]' + mixin = labeled_module("mixin") + c = labeled_module("c") {prepend mixin} + im = c.included_modules + assert_not_include(im, c, bug8025) + assert_include(im, mixin, bug8025) + c1 = labeled_class("c1") {prepend mixin} + c2 = labeled_class("c2", c1) + im = c2.included_modules + assert_not_include(im, c1, bug8025) + assert_not_include(im, c2, bug8025) + assert_include(im, mixin, bug8025) + end + + assert 'test_prepend_super_in_alias' do + bug7842 = '[Bug #7842]' + + p = labeled_module("P") do + def m; "P"+super; end + end + a = labeled_class("A") do + def m; "A"; end + end + b = labeled_class("B", a) do + def m; "B"+super; end + alias m2 m + prepend p + alias m3 m + end + assert_equal("BA", b.new.m2, bug7842) + assert_equal("PBA", b.new.m3, bug7842) + end + + assert 'test_prepend_each_classes' do + m = labeled_module("M") + c1 = labeled_class("C1") {prepend m} + c2 = labeled_class("C2", c1) {prepend m} + assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should be able to prepend each classes") + end + + assert 'test_prepend_no_duplication' do + m = labeled_module("M") + c = labeled_class("C") {prepend m; prepend m} + assert_equal([m, c], c.ancestors[0, 2], "should never duplicate") + end + + assert 'test_prepend_in_superclass' do + m = labeled_module("M") + c1 = labeled_class("C1") + c2 = labeled_class("C2", c1) {prepend m} + c1.class_eval {prepend m} + assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass") + end + + # requires #assert_seperately + #assert 'test_prepend_call_super' do + # assert_separately([], <<-'end;') #do + # bug10847 = '[ruby-core:68093] [Bug #10847]' + # module M; end + # Float.prepend M + # assert_nothing_raised(SystemStackError, bug10847) do + # 0.3.numerator + # end + # end; + #end end # @!endgroup prepend -- cgit v1.2.3 From a725cb909333335ad178997795e84c332e555c65 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Sun, 12 Jul 2015 22:07:16 +0200 Subject: Include prepended methods in the instance_methods list. --- src/kernel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index bafab6e76..36ad683ee 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -653,13 +653,19 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl { khint_t i; mrb_value ary; + mrb_bool prepended; struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); + if (!recur && klass->origin != klass) { + klass = klass->origin; + prepended = 1; + } + oldklass = 0; while (klass && (klass != oldklass)) { method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS) || + if ((klass->tt == MRB_TT_ICLASS && !prepended) || (klass->tt == MRB_TT_SCLASS)) { } else { -- cgit v1.2.3 From 11dad715784a61174b68fba57f6dc6c5311e22e3 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Sun, 12 Jul 2015 22:57:29 +0200 Subject: Enable visibility prepend tests again --- test/t/module.rb | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 7314d140f..89cc257a6 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -670,32 +670,34 @@ assert('Module#prepend') do # assert_equal(0, 1 / 2) #end - #assert 'test_prepend_visibility' do - # bug8005 = '[ruby-core:53106] [Bug #8005]' - # c = Class.new do - # prepend Module.new {} - # def foo() end - # protected :foo - # end - # a = c.new - # assert_respond_to a, [:foo, true], bug8005 - # assert_nothing_raised(NoMethodError, bug8005) {a.send :foo} - #end - - #assert 'test_prepend_visibility_inherited' do - # bug8238 = '[ruby-core:54105] [Bug #8238]' - # assert_separately [], <<-"end;", timeout: 20 - # class A - # def foo() A; end - # private :foo - # end - # class B < A - # public :foo - # prepend Module.new - # end - # assert_equal(A, B.new.foo, "#{bug8238}") - # end; - #end + # mruby has no visibility control + assert 'test_prepend_visibility' do + bug8005 = '[ruby-core:53106] [Bug #8005]' + c = Class.new do + prepend Module.new {} + def foo() end + protected :foo + end + a = c.new + assert_true a.respond_to?(:foo), bug8005 + assert_nothing_raised(NoMethodError, bug8005) {a.send :foo} + end + + # mruby has no visibility control + assert 'test_prepend_visibility_inherited' do + bug8238 = '[ruby-core:54105] [Bug #8238]' + module Test4PrependVisibilityInherited + class A + def foo() A; end + private :foo + end + class B < A + public :foo + prepend Module.new + end + end + assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") + end assert 'test_prepend_included_modules' do bug8025 = '[ruby-core:53158] [Bug #8025]' -- cgit v1.2.3 From 668153092f48275279f85d2618fff6eb9730332c Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 13 Jul 2015 09:38:24 -0500 Subject: Added Module#method_removed hook --- src/class.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class.c b/src/class.c index d83216cb4..0b00a6484 100644 --- a/src/class.c +++ b/src/class.c @@ -1945,6 +1945,7 @@ remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) k = kh_get(mt, mrb, h, mid); if (k != kh_end(h)) { kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); return; } } @@ -2197,6 +2198,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.41 */ mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); -- cgit v1.2.3 From 1f678a4acefc14531a2ed25c33f62a0d628b1474 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 13 Jul 2015 09:40:40 -0500 Subject: Removed comment beside method_removed Not sure if this apart of the ISO standard, so make sure its not misrepresented --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 0b00a6484..a13da63ac 100644 --- a/src/class.c +++ b/src/class.c @@ -2198,7 +2198,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); -- cgit v1.2.3 From 199a808e36197bd6f893112bbd43f18f2c25345f Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 13 Jul 2015 09:49:18 -0500 Subject: Bugfix, included_modules would include classes --- src/class.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index a13da63ac..5450f3a20 100644 --- a/src/class.c +++ b/src/class.c @@ -1004,7 +1004,9 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) result = mrb_ary_new(mrb); while (c) { if (c->tt == MRB_TT_ICLASS) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } } c = c->super; } -- cgit v1.2.3 From 81a2b3431c63c969f73e6c0eeaa968acbace0e44 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 13 Jul 2015 09:49:51 -0500 Subject: included_modules, origin fix Prepended modules would include their origin ICLASS --- src/class.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 5450f3a20..cde5736e0 100644 --- a/src/class.c +++ b/src/class.c @@ -1000,10 +1000,11 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c->origin; result = mrb_ary_new(mrb); while (c) { - if (c->tt == MRB_TT_ICLASS) { + if (c != origin && c->tt == MRB_TT_ICLASS) { if (c->c->tt == MRB_TT_MODULE) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } -- cgit v1.2.3 From 11cb41770dc7b36edac0af1e6784bd40d1c8243c Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 13 Jul 2015 10:42:33 -0500 Subject: Space out test_prepend_super_in_alias assert Also tried to fix it, however the problem lies with how aliased methods are done and their internal structure. mruby simply aliases methods by grabbing the RProc and giving it a new name, super then determines the original method to call by using the name so a method called m, aliased as m2, will call the m2 super method instead of m --- test/t/module.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 89cc257a6..605ca28a7 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -720,17 +720,25 @@ assert('Module#prepend') do p = labeled_module("P") do def m; "P"+super; end end + a = labeled_class("A") do def m; "A"; end end + b = labeled_class("B", a) do def m; "B"+super; end alias m2 m prepend p alias m3 m end - assert_equal("BA", b.new.m2, bug7842) - assert_equal("PBA", b.new.m3, bug7842) + + assert_nothing_raised do + assert_equal("BA", b.new.m2, bug7842) + end + + assert_nothing_raised do + assert_equal("PBA", b.new.m3, bug7842) + end end assert 'test_prepend_each_classes' do -- cgit v1.2.3 From b0fb9ccfd8cb5986ea153142687cfbed1a876d6b Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 13 Jul 2015 23:25:01 +0200 Subject: Enable test_prepend_module_ancestors because it seems to pass. --- test/t/module.rb | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 605ca28a7..7b4a8fec7 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -611,33 +611,33 @@ assert('Module#prepend') do end # this assertion causes the mrbtest to segfault - #assert 'test_prepend_module_ancestors' do - # bug6659 = '[ruby-dev:45861]' - # m0 = labeled_module("m0") { def x; [:m0, *super] end } - # m1 = labeled_module("m1") { def x; [:m1, *super] end; prepend m0 } - # m2 = labeled_module("m2") { def x; [:m2, *super] end; prepend m1 } - # c0 = labeled_class("c0") { def x; [:c0] end } - # c1 = labeled_class("c1") { def x; [:c1] end; prepend m2 } - # c2 = labeled_class("c2", c0) { def x; [:c2, *super] end; include m2 } - # # - # assert_equal([m0, m1], m1.ancestors, bug6659) - # # - # bug6662 = '[ruby-dev:45868]' - # assert_equal([m0, m1, m2], m2.ancestors, bug6662) - # assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) - # assert_equal([:m0, :m1, :m2, :c1], c1.new.x) - # assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) - # assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x) - # # - # m3 = labeled_module("m3") { include m1; prepend m1 } - # assert_equal([m3, m0, m1], m3.ancestors) - # m3 = labeled_module("m3") { prepend m1; include m1 } - # assert_equal([m0, m1, m3], m3.ancestors) - # m3 = labeled_module("m3") { prepend m1; prepend m1 } - # assert_equal([m0, m1, m3], m3.ancestors) - # m3 = labeled_module("m3") { include m1; include m1 } - # assert_equal([m3, m0, m1], m3.ancestors) - #end + assert 'test_prepend_module_ancestors' do + bug6659 = '[ruby-dev:45861]' + m0 = labeled_module("m0") { def x; [:m0, *super] end } + m1 = labeled_module("m1") { def x; [:m1, *super] end; prepend m0 } + m2 = labeled_module("m2") { def x; [:m2, *super] end; prepend m1 } + c0 = labeled_class("c0") { def x; [:c0] end } + c1 = labeled_class("c1") { def x; [:c1] end; prepend m2 } + c2 = labeled_class("c2", c0) { def x; [:c2, *super] end; include m2 } + # + assert_equal([m0, m1], m1.ancestors, bug6659) + # + bug6662 = '[ruby-dev:45868]' + assert_equal([m0, m1, m2], m2.ancestors, bug6662) + assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) + assert_equal([:m0, :m1, :m2, :c1], c1.new.x) + assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) + assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x) + # + m3 = labeled_module("m3") { include m1; prepend m1 } + assert_equal([m3, m0, m1], m3.ancestors) + m3 = labeled_module("m3") { prepend m1; include m1 } + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") { prepend m1; prepend m1 } + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") { include m1; include m1 } + assert_equal([m3, m0, m1], m3.ancestors) + end assert 'test_prepend_instance_methods_false' do bug6660 = '[ruby-dev:45863]' -- cgit v1.2.3 From 8c13e2b7c6e6c1c02771e4f9e5aebda109892503 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 13 Jul 2015 23:35:30 +0200 Subject: Set origin when doing kind_of? comparisons --- src/object.c | 1 + test/t/module.rb | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/object.c b/src/object.c index f8f41bfe8..c834ee04f 100644 --- a/src/object.c +++ b/src/object.c @@ -487,6 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); } + c = c->origin; while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; diff --git a/test/t/module.rb b/test/t/module.rb index 7b4a8fec7..a1996f5f6 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -543,21 +543,21 @@ assert('Module#prepend') do b = labeled_module('b') { include a } c = labeled_module('c') { prepend b } - assert bug6654 do + #assert bug6654 do # the Module#< operator should be used here instead, but we don't have it assert_include(c.ancestors, a) assert_include(c.ancestors, b) - end + #end bug8357 = '[ruby-core:54736] [Bug #8357]' b = labeled_module('b') { prepend a } c = labeled_class('c') { include b } - assert bug8357 do + #assert bug8357 do # the Module#< operator should be used here instead, but we don't have it assert_include(c.ancestors, a) assert_include(c.ancestors, b) - end + #end bug8357 = '[ruby-core:54742] [Bug #8357]' assert_kind_of(b, c.new, bug8357) -- cgit v1.2.3 From 8c4da7accd98fb36e3f1f5f9e4ea069244345858 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 13 Jul 2015 23:38:37 +0200 Subject: assert() cannot be nested --- test/t/module.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index a1996f5f6..5aba53c46 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -495,7 +495,6 @@ end # Not ISO specified # @!group prepend -assert('Module#prepend') do assert('test_prepend') do module M0 def m1; [:M0] end @@ -773,7 +772,6 @@ assert('Module#prepend') do # end # end; #end -end # @!endgroup prepend assert('Module#to_s') do -- cgit v1.2.3 From 78462c9181ccbc92d26a466c5a3f06aec2d2f714 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 13 Jul 2015 23:46:25 +0200 Subject: Clean up tests --- test/t/module.rb | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index 5aba53c46..4bde20fbe 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -495,7 +495,7 @@ end # Not ISO specified # @!group prepend - assert('test_prepend') do + assert('Module#prepend') do module M0 def m1; [:M0] end end @@ -530,13 +530,13 @@ end # mruby shouldn't be affected by this since there is # no visibility control (yet) - assert('test_public_prepend') do + assert('Module#prepend public') do assert_nothing_raised('ruby/ruby #8846') do Class.new.prepend(Module.new) end end - assert('test_prepend_inheritance') do + assert('Module#prepend inheritance') do bug6654 = '[ruby-core:45914]' a = labeled_module('a') b = labeled_module('b') { include a } @@ -562,18 +562,18 @@ end assert_kind_of(b, c.new, bug8357) end - assert('test_prepend_instance_methods') do + assert('Moduler#prepend + #instance_methods') do bug6655 = '[ruby-core:45915]' assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) end - assert 'test_prepend_singleton_methods' do + assert 'Module#prepend + #singleton_methods' do o = Object.new o.singleton_class.class_eval {prepend Module.new} assert_equal([], o.singleton_methods) end - assert 'test_prepend_remove_method' do + assert 'Module#prepend + #remove_method' do c = Class.new do prepend Module.new { def foo; end } end @@ -597,7 +597,7 @@ end assert_equal(:foo, removed) end - assert 'test_prepend_class_ancestors' do + assert 'Module#prepend + Class#ancestors' do bug6658 = '[ruby-core:45919]' m = labeled_module("m") c = labeled_class("c") {prepend m} @@ -609,8 +609,7 @@ end assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662) end - # this assertion causes the mrbtest to segfault - assert 'test_prepend_module_ancestors' do + assert 'Module#prepend + Module#ancestors' do bug6659 = '[ruby-dev:45861]' m0 = labeled_module("m0") { def x; [:m0, *super] end } m1 = labeled_module("m1") { def x; [:m1, *super] end; prepend m0 } @@ -638,13 +637,13 @@ end assert_equal([m3, m0, m1], m3.ancestors) end - assert 'test_prepend_instance_methods_false' do + assert 'Module#prepend #instance_methods(false)' do bug6660 = '[ruby-dev:45863]' assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) end - assert 'test_cyclic_prepend' do + assert 'cyclic Module#prepend' do bug7841 = '[ruby-core:52205] [Bug #7841]' m1 = Module.new m2 = Module.new @@ -670,7 +669,7 @@ end #end # mruby has no visibility control - assert 'test_prepend_visibility' do + assert 'Module#prepend visibility' do bug8005 = '[ruby-core:53106] [Bug #8005]' c = Class.new do prepend Module.new {} @@ -683,7 +682,7 @@ end end # mruby has no visibility control - assert 'test_prepend_visibility_inherited' do + assert 'Module#prepend inherited visibility' do bug8238 = '[ruby-core:54105] [Bug #8238]' module Test4PrependVisibilityInherited class A @@ -698,7 +697,7 @@ end assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") end - assert 'test_prepend_included_modules' do + assert 'Module#prepend + #included_modules' do bug8025 = '[ruby-core:53158] [Bug #8025]' mixin = labeled_module("mixin") c = labeled_module("c") {prepend mixin} @@ -713,7 +712,8 @@ end assert_include(im, mixin, bug8025) end - assert 'test_prepend_super_in_alias' do + assert 'Module#prepend super in alias' do + skip "super does not currently work in aliased methods" bug7842 = '[Bug #7842]' p = labeled_module("P") do @@ -740,20 +740,20 @@ end end end - assert 'test_prepend_each_classes' do + assert 'Module#prepend each class' do m = labeled_module("M") c1 = labeled_class("C1") {prepend m} c2 = labeled_class("C2", c1) {prepend m} - assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should be able to prepend each classes") + assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should be able to prepend each class") end - assert 'test_prepend_no_duplication' do + assert 'Module#prepend no duplication' do m = labeled_module("M") c = labeled_class("C") {prepend m; prepend m} assert_equal([m, c], c.ancestors[0, 2], "should never duplicate") end - assert 'test_prepend_in_superclass' do + assert 'Module#prepend in superclass' do m = labeled_module("M") c1 = labeled_class("C1") c2 = labeled_class("C2", c1) {prepend m} @@ -762,7 +762,7 @@ end end # requires #assert_seperately - #assert 'test_prepend_call_super' do + #assert 'Module#prepend call super' do # assert_separately([], <<-'end;') #do # bug10847 = '[ruby-core:68093] [Bug #10847]' # module M; end -- cgit v1.2.3 From a0754986134fbe6b65992b19338c97d596f4ef60 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 14 Jul 2015 13:22:42 +0900 Subject: mrb_get_args: allow A,H,s,z,a,d specifiers to take ! to accept nil. S,A,H gives nil, s,z,a,d gives NULL for nil argument. ref 02474da --- src/class.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/class.c b/src/class.c index 8a9fdaca6..b5f5f5287 100644 --- a/src/class.c +++ b/src/class.c @@ -435,9 +435,9 @@ to_sym(mrb_state *mrb, mrb_value ss) ---------------------------------------------------------------------------------------------- o: Object [mrb_value] C: class/module [mrb_value] - S: String [mrb_value] when ! follows the value may be nil - A: Array [mrb_value] - H: Hash [mrb_value] + S: String [mrb_value] when ! follows, the value may be nil + A: Array [mrb_value] when ! follows, the value may be nil + H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments. z: String [char*] NUL terminated string. a: Array [mrb_value*,mrb_int] Receive two arguments. @@ -527,7 +527,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (*format == '!') { format++; - if (mrb_nil_p(*sp)) { + if (i < argc && mrb_nil_p(*sp)) { *p = *sp++; i++; break; @@ -544,6 +544,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_ary(mrb, *sp++); i++; @@ -555,6 +563,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *p = *sp++; + i++; + break; + } + } if (i < argc) { *p = to_hash(mrb, *sp++); i++; @@ -569,6 +585,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, char**); pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *ps = NULL; + *pl = 0; + i++; + break; + } + } if (i < argc) { ss = to_str(mrb, *sp++); *ps = RSTRING_PTR(ss); @@ -583,6 +608,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps; ps = va_arg(ap, const char**); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *ps = NULL; + i++; + break; + } + } if (i < argc) { ss = to_str(mrb, *sp++); *ps = mrb_string_value_cstr(mrb, &ss); @@ -599,6 +632,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *pb = 0; + *pl = 0; + i++; + break; + } + } if (i < argc) { aa = to_ary(mrb, *sp++); a = mrb_ary_ptr(aa); -- cgit v1.2.3 From 4e7050fe0c56a9403f182d3f79a22a4196d377f0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 14 Jul 2015 13:34:21 +0900 Subject: mrb_get_args: allow d! --- src/class.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/class.c b/src/class.c index b5f5f5287..b306cb489 100644 --- a/src/class.c +++ b/src/class.c @@ -726,6 +726,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) datap = va_arg(ap, void**); type = va_arg(ap, struct mrb_data_type const*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(*sp)) { + *datap = 0; + i++; + break; + } + } if (i < argc) { *datap = mrb_data_get_ptr(mrb, *sp++, type); ++i; -- cgit v1.2.3 From 53a81da0fafc2adbc791d9f161207faa29bccb4e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 14 Jul 2015 13:35:06 +0900 Subject: mrb_get_args: improve function description about ! --- src/class.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class.c b/src/class.c index b306cb489..1d54c91f4 100644 --- a/src/class.c +++ b/src/class.c @@ -438,9 +438,9 @@ to_sym(mrb_state *mrb, mrb_value ss) S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil - s: String [char*,mrb_int] Receive two arguments. - z: String [char*] NUL terminated string. - a: Array [mrb_value*,mrb_int] Receive two arguments. + s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil + z: String [char*] NUL terminated string; z! gives NULL for nil + a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil f: Float [mrb_float] i: Integer [mrb_int] b: Boolean [mrb_bool] -- cgit v1.2.3 From 510e53d89f447b900a028f75c51ba18cb95d1670 Mon Sep 17 00:00:00 2001 From: jbreeden Date: Mon, 13 Jul 2015 23:21:19 -0700 Subject: Add ! documentation to mruby.h.md --- doc/api/mruby.h.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 8862fee2c..8236b8244 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -43,20 +43,22 @@ Deletes `mrb_state`. int mrb_get_args(mrb_state *mrb, const char *format, ...); ``` Retrieve arguments from `mrb_state`. +When applicable, implicit conversions (such as `to_str`, +`to_ary`, `to_hash`) are be applied to received arguments. Use it inside a function pointed by `mrb_func_t`. -It returns number of function retrieved. -`format` is a list of following format specifier: +It returns the number of arguments retrieved. +`format` is a list of following format specifiers: char|mruby type|retrieve types|note :---:|----------|--------------|--- `o`|`Object`|`mrb_value`|Could be used to retrieve any type of argument `C`|`Class`/`Module`|`mrb_value`| -`S`|`String`|`mrb_value`| -`A`|`Array`|`mrb_value`| -`H`|`Hash`|`mrb_value`| -`s`|`String`|`char*`, `mrb_int`| -`z`|`String`|`char*`| -`a`|`Array`|`mrb_value*`, `mrb_int`| +`S`|`String`|`mrb_value`|when ! follows, the value may be nil +`A`|`Array`|`mrb_value`|when ! follows, the value may be nil +`H`|`Hash`|`mrb_value`|when ! follows, the value may be nil +`s`|`String`|`char*`, `mrb_int`|Receive two arguments; s! gives (NULL,0) for nil +`z`|`String`|`char*`|NUL terminated string; z! gives NULL for nil +`a`|`Array`|`mrb_value*`, `mrb_int`|Receive two arguments; a! gives (NULL,0) for nil `f`|`Float`|`mrb_float`| `i`|`Integer`|`mrb_int`| `b`|boolean|`mrb_bool`| @@ -118,7 +120,7 @@ mrb_value example_method(mrb_state* mrb, mrb_value self){ void mrb_example_gem_init(mrb_state* mrb) { struct RClass *example_class; example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); - mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); + mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); } void mrb_example_gem_final(mrb_state* mrb) { -- cgit v1.2.3 From e92da7b76c75b0270fc4a9bfd8c8dd20985e1f00 Mon Sep 17 00:00:00 2001 From: jbreeden Date: Mon, 13 Jul 2015 23:26:29 -0700 Subject: Fix typo --- doc/api/mruby.h.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 8236b8244..06bab2d56 100644 --- a/doc/api/mruby.h.md +++ b/doc/api/mruby.h.md @@ -44,7 +44,7 @@ int mrb_get_args(mrb_state *mrb, const char *format, ...); ``` Retrieve arguments from `mrb_state`. When applicable, implicit conversions (such as `to_str`, -`to_ary`, `to_hash`) are be applied to received arguments. +`to_ary`, `to_hash`) are applied to received arguments. Use it inside a function pointed by `mrb_func_t`. It returns the number of arguments retrieved. `format` is a list of following format specifiers: -- cgit v1.2.3 From f0e920baf07e17fd1073566d7e9605f9192d766d Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Tue, 14 Jul 2015 08:55:53 -0500 Subject: Renamed parameters in include_module_at --- src/class.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/class.c b/src/class.c index cde5736e0..14d81495e 100644 --- a/src/class.c +++ b/src/class.c @@ -798,26 +798,26 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) } MRB_API int -include_module_at(mrb_state *mrb, struct RClass *klass, struct RClass *c, struct RClass *module, int search_super) +include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) { - struct RClass *p, *iclass; - void *klass_mt = klass->origin->mt; + struct RClass *p, *ic; + void *klass_mt = c->origin->mt; - while (module) { + while (m) { int superclass_seen = 0; - if (module->origin != module) + if (m->origin != m) goto skip; - if (klass_mt && klass_mt == module->mt) + if (klass_mt && klass_mt == m->mt) return -1; - p = klass->super; + p = c->super; while(p) { if (p->tt == MRB_TT_ICLASS) { - if (p->mt == module->mt) { + if (p->mt == m->mt) { if (!superclass_seen) { - c = p; // move insert point + ins_pos = p; // move insert point } goto skip; } @@ -828,12 +828,12 @@ include_module_at(mrb_state *mrb, struct RClass *klass, struct RClass *c, struct p = p->super; } - iclass = include_class_new(mrb, module, c->super); - c->super = iclass; - mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->super); - c = iclass; + ic = include_class_new(mrb, m, ins_pos->super); + ins_pos->super = ic; + mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ins_pos->super); + ins_pos = ic; skip: - module = module->super; + m = m->super; } return 0; } -- cgit v1.2.3 From eb172c28d79b4fdf978e78fc7e929caa855dd29b Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Tue, 14 Jul 2015 09:44:04 -0500 Subject: Applied gc patch to fix ORIGIN ICLASS method table leak Based on the gc patch by ko1 https://github.com/ruby/ruby/commit/5922c954614e5947a548780bb3b894626affe6dd --- include/mruby/class.h | 7 +++++-- include/mruby/object.h | 2 ++ src/class.c | 1 + src/gc.c | 12 ++++++++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 60310ae9d..9f2c32bb0 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -49,8 +49,11 @@ mrb_class(mrb_state *mrb, mrb_value v) } } -#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~0xff) | (char)tt) -#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & 0xff) +// TODO: figure out where to put user flags +#define MRB_FLAG_IS_ORIGIN (1 << 20) +#define MRB_FLAG_IS_INSTANCE (0xFF) +#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_FLAG_IS_INSTANCE) | (char)tt) +#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_FLAG_IS_INSTANCE) MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); diff --git a/include/mruby/object.h b/include/mruby/object.h index fe55620fe..6633a23e8 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -14,6 +14,8 @@ struct RClass *c;\ struct RBasic *gcnext +#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag) + /* white: 011, black: 100, gray: 000 */ #define MRB_GC_GRAY 0 #define MRB_GC_WHITE_A 1 diff --git a/src/class.c b/src/class.c index 14d81495e..58742299b 100644 --- a/src/class.c +++ b/src/class.c @@ -856,6 +856,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) origin = c->origin; if (origin == c) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); + origin->flags |= MRB_FLAG_IS_ORIGIN; origin->origin = origin; origin->super = c->super; c->super = origin; diff --git a/src/gc.c b/src/gc.c index 8bd8243f1..15e1bd423 100644 --- a/src/gc.c +++ b/src/gc.c @@ -498,7 +498,12 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) mrb_gc_mark(mrb, (struct RBasic*)obj->c); switch (obj->tt) { case MRB_TT_ICLASS: - mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); + { + struct RClass *c = (struct RClass*)obj; + if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN)) + mrb_gc_mark_mt(mrb, c); + mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); + } break; case MRB_TT_CLASS: @@ -624,7 +629,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj) mrb_gc_free_mt(mrb, (struct RClass*)obj); mrb_gc_free_iv(mrb, (struct RObject*)obj); break; - + case MRB_TT_ICLASS: + if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + mrb_gc_free_mt(mrb, (struct RClass*)obj); + break; case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; -- cgit v1.2.3 From dbbf2e26231c04d76badb1889627869d1f9361bb Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Tue, 14 Jul 2015 14:12:23 -0500 Subject: Remove non-applicable "hack" comment --- src/class.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/class.c b/src/class.c index 58742299b..f342ded20 100644 --- a/src/class.c +++ b/src/class.c @@ -1020,8 +1020,6 @@ static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; - - /* hack, fix missing module->origin */ struct RClass *m = mrb_class_ptr(mod); boot_initmod(mrb, m); // bootstrap a newly initialized module mrb_get_args(mrb, "|&", &b); -- cgit v1.2.3 From 2e4bc2de8889a321fbde9898bc9afc9daefd8f76 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 00:05:07 +0900 Subject: Refactor `Build#compile_as_cxx`. --- tasks/mruby_build.rake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 947b4ba77..9f8b4eda5 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -127,8 +127,8 @@ module MRuby obj = objfile(cxx_src) if obj.nil? file cxx_src => [src, __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write < cxx_src do |t| -- cgit v1.2.3 From cdd72d9c3783749c979edf62522cf9636681538d Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 00:05:45 +0900 Subject: Implement `mrb_protect`, `mrb_ensure`, `mrb_rescue`, `mrb_rescue_exceptions`. (`mrb_rescue_exceptions` is mruby implementation of `rb_rescue2`.) Closes #2844, closes #2837. --- include/mruby/error.h | 8 +++ mrbgems/mruby-error/mrbgem.rake | 10 ++++ mrbgems/mruby-error/src/exception.c | 102 ++++++++++++++++++++++++++++++++++ mrbgems/mruby-error/test/exception.c | 57 +++++++++++++++++++ mrbgems/mruby-error/test/exception.rb | 53 ++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 mrbgems/mruby-error/mrbgem.rake create mode 100644 mrbgems/mruby-error/src/exception.c create mode 100644 mrbgems/mruby-error/test/exception.c create mode 100644 mrbgems/mruby-error/test/exception.rb diff --git a/include/mruby/error.h b/include/mruby/error.h index 282be0a24..3a985236a 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -29,6 +29,14 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va /* declaration for fail method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); +MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state); +MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t ensure, mrb_value e_data); +MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data); +MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data, ...); + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/mrbgems/mruby-error/mrbgem.rake b/mrbgems/mruby-error/mrbgem.rake new file mode 100644 index 000000000..b8281b17e --- /dev/null +++ b/mrbgems/mruby-error/mrbgem.rake @@ -0,0 +1,10 @@ +MRuby::Gem::Specification.new('mruby-error') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'extensional error handling' + + if build.cxx_abi_enabled? + @objs << build.compile_as_cxx("#{spec.dir}/src/exception.c", "#{spec.build_dir}/src/exception.cxx") + @objs.delete_if { |v| v == objfile("#{spec.build_dir}/src/exception") } + end +end diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c new file mode 100644 index 000000000..abd03bc29 --- /dev/null +++ b/mrbgems/mruby-error/src/exception.c @@ -0,0 +1,102 @@ +#include +#include "mruby.h" +#include "mruby/throw.h" +#include "mruby/error.h" + +MRB_API mrb_value +mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result = mrb_nil_value(); + + if (state) { *state = FALSE; } + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + mrb->exc = NULL; + if (state) { *state = TRUE; } + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t ensure, mrb_value e_data) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + ensure(mrb, e_data); + MRB_THROW(mrb->jmp); /* rethrow catched exceptions */ + } MRB_END_EXC(&c_jmp); + + ensure(mrb, e_data); + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data) +{ + return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, mrb->eStandardError_class, NULL); +} + +MRB_API mrb_value +mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, ...) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + va_list excs; + struct RClass *cls; + mrb_bool error_matched = FALSE; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + + va_start(excs, r_data); + while((cls = va_arg(excs, struct RClass*))) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), cls)) { + error_matched = TRUE; + break; + } + } + va_end(excs); + + if (!error_matched) { MRB_THROW(mrb->jmp); } + + mrb->exc = NULL; + result = rescue(mrb, r_data); + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +void +mrb_mruby_error_gem_init(mrb_state *mrb) +{ +} + +void +mrb_mruby_error_gem_final(mrb_state *mrb) +{ +} diff --git a/mrbgems/mruby-error/test/exception.c b/mrbgems/mruby-error/test/exception.c new file mode 100644 index 000000000..7c15fb457 --- /dev/null +++ b/mrbgems/mruby-error/test/exception.c @@ -0,0 +1,57 @@ +#include "mruby.h" +#include "mruby/error.h" +#include "mruby/array.h" + +static mrb_value +protect_cb(mrb_state *mrb, mrb_value b) +{ + return mrb_yield_argv(mrb, b, 0, NULL); +} + +static mrb_value +run_protect(mrb_state *mrb, mrb_value self) +{ + mrb_value b; + mrb_value ret[2]; + mrb_bool state; + mrb_get_args(mrb, "&", &b); + ret[0] = mrb_protect(mrb, protect_cb, b, &state); + ret[1] = mrb_bool_value(state); + return mrb_ary_new_from_values(mrb, 2, ret); +} + +static mrb_value +run_ensure(mrb_state *mrb, mrb_value self) +{ + mrb_value b, e; + mrb_get_args(mrb, "oo", &b, &e); + return mrb_ensure(mrb, protect_cb, b, protect_cb, e); +} + +static mrb_value +run_rescue(mrb_state *mrb, mrb_value self) +{ + mrb_value b, r; + mrb_get_args(mrb, "oo", &b, &r); + return mrb_rescue(mrb, protect_cb, b, protect_cb, r); +} + +static mrb_value +run_rescue_exceptions(mrb_state *mrb, mrb_value self) +{ + mrb_value b, r; + mrb_get_args(mrb, "oo", &b, &r); + return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, E_TYPE_ERROR, NULL); +} + +void +mrb_mruby_error_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "ExceptionTest", mrb->object_class); + mrb_define_module_function(mrb, cls, "mrb_protect", run_protect, MRB_ARGS_NONE() | MRB_ARGS_BLOCK()); + mrb_define_module_function(mrb, cls, "mrb_ensure", run_ensure, MRB_ARGS_REQ(2)); + mrb_define_module_function(mrb, cls, "mrb_rescue", run_rescue, MRB_ARGS_REQ(2)); + mrb_define_module_function(mrb, cls, "mrb_rescue_exceptions", run_rescue_exceptions, MRB_ARGS_REQ(2)); +} diff --git a/mrbgems/mruby-error/test/exception.rb b/mrbgems/mruby-error/test/exception.rb new file mode 100644 index 000000000..b5ea719a2 --- /dev/null +++ b/mrbgems/mruby-error/test/exception.rb @@ -0,0 +1,53 @@ +assert 'mrb_protect' do + assert_equal ['test', false] do + ExceptionTest.mrb_protect { 'test' } + end + assert_equal [nil, true] do + ExceptionTest.mrb_protect { raise 'test' } + end +end + +assert 'mrb_ensure' do + a = false + assert_equal 'test' do + ExceptionTest.mrb_ensure Proc.new { 'test' }, Proc.new { a = true } + end + assert_true a + + a = false + assert_raise RuntimeError do + ExceptionTest.mrb_ensure Proc.new { raise 'test' }, Proc.new { a = true } + end + assert_true a +end + +assert 'mrb_rescue' do + assert_equal 'test' do + ExceptionTest.mrb_rescue Proc.new { 'test' }, Proc.new {} + end + + class CustomExp < Exception + end + + assert_raise CustomExp do + ExceptionTest.mrb_rescue Proc.new { raise CustomExp.new 'test' }, Proc.new { 'rescue' } + end + + assert_equal 'rescue' do + ExceptionTest.mrb_rescue Proc.new { raise 'test' }, Proc.new { 'rescue' } + end +end + +assert 'mrb_rescue_exceptions' do + assert_equal 'test' do + ExceptionTest.mrb_rescue_exceptions Proc.new { 'test' }, Proc.new {} + end + + assert_raise RangeError do + ExceptionTest.mrb_rescue_exceptions Proc.new { raise RangeError.new 'test' }, Proc.new { 'rescue' } + end + + assert_equal 'rescue' do + ExceptionTest.mrb_rescue_exceptions Proc.new { raise TypeError.new 'test' }, Proc.new { 'rescue' } + end +end -- cgit v1.2.3 From f6b5a829729479d4ae557effc15656605ca71781 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 10:49:37 +0900 Subject: Use class array instead of variadic. --- include/mruby/error.h | 3 ++- mrbgems/mruby-error/src/exception.c | 14 ++++++-------- mrbgems/mruby-error/test/exception.c | 4 +++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/mruby/error.h b/include/mruby/error.h index 3a985236a..d02e9166c 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -35,7 +35,8 @@ MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data); MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, - mrb_func_t rescue, mrb_value r_data, ...); + mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index abd03bc29..7199e0801 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -1,4 +1,3 @@ -#include #include "mruby.h" #include "mruby/throw.h" #include "mruby/error.h" @@ -52,18 +51,19 @@ MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data) { - return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, mrb->eStandardError_class, NULL); + return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, 1, &mrb->eStandardError_class); } MRB_API mrb_value -mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, ...) +mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes) { struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; mrb_value result; - va_list excs; struct RClass *cls; mrb_bool error_matched = FALSE; + mrb_int i; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; @@ -72,14 +72,12 @@ mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_fun } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; - va_start(excs, r_data); - while((cls = va_arg(excs, struct RClass*))) { - if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), cls)) { + for (i = 0; i < len; ++i) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), classes[i])) { error_matched = TRUE; break; } } - va_end(excs); if (!error_matched) { MRB_THROW(mrb->jmp); } diff --git a/mrbgems/mruby-error/test/exception.c b/mrbgems/mruby-error/test/exception.c index 7c15fb457..2a943aaae 100644 --- a/mrbgems/mruby-error/test/exception.c +++ b/mrbgems/mruby-error/test/exception.c @@ -40,8 +40,10 @@ static mrb_value run_rescue_exceptions(mrb_state *mrb, mrb_value self) { mrb_value b, r; + struct RClass *cls[1]; mrb_get_args(mrb, "oo", &b, &r); - return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, E_TYPE_ERROR, NULL); + cls[0] = E_TYPE_ERROR; + return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, 1, cls); } void -- cgit v1.2.3 From c0bf76d0a1ef631813c01d785500c1544d18a506 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Jul 2015 14:43:34 +0900 Subject: remove unused variable declaration --- mrbgems/mruby-error/src/exception.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index 7199e0801..9d77c6adf 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -61,7 +61,6 @@ mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_fun struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; mrb_value result; - struct RClass *cls; mrb_bool error_matched = FALSE; mrb_int i; -- cgit v1.2.3 From 1085167fefe010be8e2d39e2adb31134a5512b15 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Jul 2015 14:44:19 +0900 Subject: add an small comment description in mruby/error.h header --- include/mruby/error.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mruby/error.h b/include/mruby/error.h index d02e9166c..e3e2b25e2 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -29,6 +29,7 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va /* declaration for fail method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); +/* functions defined in mruby-error mrbgem */ MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state); MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t ensure, mrb_value e_data); -- cgit v1.2.3 From 207577f0af72874d9d643f2c46b881a9159d42d7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Jul 2015 14:45:32 +0900 Subject: mrb_protect() to return the exception raised (with the state of true) --- mrbgems/mruby-error/src/exception.c | 1 + mrbgems/mruby-error/test/exception.rb | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index 9d77c6adf..911fde0be 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -17,6 +17,7 @@ mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state) mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; + result = mrb_obj_value(mrb->exc); mrb->exc = NULL; if (state) { *state = TRUE; } } MRB_END_EXC(&c_jmp); diff --git a/mrbgems/mruby-error/test/exception.rb b/mrbgems/mruby-error/test/exception.rb index b5ea719a2..0bbc2a0e7 100644 --- a/mrbgems/mruby-error/test/exception.rb +++ b/mrbgems/mruby-error/test/exception.rb @@ -1,10 +1,12 @@ assert 'mrb_protect' do + # no failure in protect returns [result, false] assert_equal ['test', false] do ExceptionTest.mrb_protect { 'test' } end - assert_equal [nil, true] do - ExceptionTest.mrb_protect { raise 'test' } - end + # failure in protect returns [exception, true] + result = ExceptionTest.mrb_protect { raise 'test' } + assert_kind_of RuntimeError, result[0] + assert_true result[1] end assert 'mrb_ensure' do -- cgit v1.2.3 From 667f7788db2b3b78cc4cc65c0f37ab38347116c5 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Wed, 15 Jul 2015 07:27:31 -0500 Subject: Renamed MRB_FLAG_IS_INSTANCE to MRB_INSTANCE_TT_MASK --- include/mruby/class.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 9f2c32bb0..80a0cbe35 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -51,9 +51,9 @@ mrb_class(mrb_state *mrb, mrb_value v) // TODO: figure out where to put user flags #define MRB_FLAG_IS_ORIGIN (1 << 20) -#define MRB_FLAG_IS_INSTANCE (0xFF) -#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_FLAG_IS_INSTANCE) | (char)tt) -#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_FLAG_IS_INSTANCE) +#define MRB_INSTANCE_TT_MASK (0xFF) +#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) +#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); -- cgit v1.2.3 From 938ed044f4e053c1832be3868230d80ccba190e8 Mon Sep 17 00:00:00 2001 From: cremno Date: Thu, 16 Jul 2015 03:56:31 +0200 Subject: use mrb_str_cat_str() instead of mrb_str_append() If the argument is always a string, then mrb_str_cat_str() can be directly called instead of indirectly by mrb_str_append(). mrb_any_to_s(), mrb_obj_as_string(), mrb_inspect() always return a string. --- src/class.c | 4 ++-- src/error.c | 4 ++-- src/range.c | 4 ++-- src/variable.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/class.c b/src/class.c index 1d54c91f4..33fb61211 100644 --- a/src/class.c +++ b/src/class.c @@ -1608,10 +1608,10 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: - mrb_str_append(mrb, str, mrb_inspect(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); break; default: - mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v)); break; } return mrb_str_cat_lit(mrb, str, ">"); diff --git a/src/error.c b/src/error.c index 20c63bd43..359e5737b 100644 --- a/src/error.c +++ b/src/error.c @@ -152,7 +152,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) mrb_str_append(mrb, str, line); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); mrb_str_cat_lit(mrb, str, " ("); } mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); @@ -165,7 +165,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) str = mrb_str_new_cstr(mrb, cname); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); } else { mrb_str_cat_cstr(mrb, str, cname); diff --git a/src/range.c b/src/range.c index b427dc1b7..b58b6a1c8 100644 --- a/src/range.c +++ b/src/range.c @@ -290,7 +290,7 @@ range_to_s(mrb_state *mrb, mrb_value range) str2 = mrb_obj_as_string(mrb, r->edges->end); str = mrb_str_dup(mrb, str); mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); - mrb_str_append(mrb, str, str2); + mrb_str_cat_str(mrb, str, str2); return str; } @@ -315,7 +315,7 @@ range_inspect(mrb_state *mrb, mrb_value range) str2 = mrb_inspect(mrb, r->edges->end); str = mrb_str_dup(mrb, str); mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); - mrb_str_append(mrb, str, str2); + mrb_str_cat_str(mrb, str, str2); return str; } diff --git a/src/variable.c b/src/variable.c index 1b2ad56a7..efe6fad12 100644 --- a/src/variable.c +++ b/src/variable.c @@ -609,7 +609,7 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) else { ins = mrb_inspect(mrb, v); } - mrb_str_append(mrb, str, ins); + mrb_str_cat_str(mrb, str, ins); return 0; } -- cgit v1.2.3 From 0f284091d161dbca6e07de85896cbdc9abd2de6b Mon Sep 17 00:00:00 2001 From: cremno Date: Thu, 16 Jul 2015 04:58:21 +0200 Subject: delete mrb_free()-related non-NULL checks No need to optimize since a program only exits once and errors are rare. Also the mruby source code doesn't have these kind of checks elsewhere. The ones in {Time,Random}#initialize are kept because there it actually matters since initialization always happens and re-initialization is unlikely. --- mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c | 3 +-- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 5 ++--- src/dump.c | 8 ++------ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index f27f87a5d..301dde1c6 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -161,8 +161,7 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) static void cleanup(mrb_state *mrb, struct mrbc_args *args) { - if (args->outfile) - mrb_free(mrb, (void*)args->outfile); + mrb_free(mrb, (void*)args->outfile); mrb_close(mrb); } diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 141ea151b..5ca744388 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -159,10 +159,9 @@ cleanup(mrb_state *mrb, struct _args *args) { if (args->rfp && args->rfp != stdin) fclose(args->rfp); - if (args->cmdline && !args->fname) + if (!args->fname) mrb_free(mrb, args->cmdline); - if (args->argv) - mrb_free(mrb, args->argv); + mrb_free(mrb, args->argv); mrb_close(mrb); } diff --git a/src/dump.c b/src/dump.c index 2f2e5edcb..462e036b4 100644 --- a/src/dump.c +++ b/src/dump.c @@ -978,12 +978,8 @@ error_exit: mrb_free(mrb, *bin); *bin = NULL; } - if (lv_syms) { - mrb_free(mrb, lv_syms); - } - if (filenames) { - mrb_free(mrb, filenames); - } + mrb_free(mrb, lv_syms); + mrb_free(mrb, filenames); return result; } -- cgit v1.2.3 From 67e187f0f883789131c596ccc56980c32471bbbf Mon Sep 17 00:00:00 2001 From: takkaw Date: Thu, 16 Jul 2015 18:40:07 +0900 Subject: 64bit Cygwin also doesn't have frexpl(3) --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index b467435a3..b27ebd6e9 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -90,7 +90,7 @@ fmt_u(uint32_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -#if ((defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) +#if ((defined(__CYGWIN__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) #undef frexpl #define frexpl frexp #endif -- cgit v1.2.3 From ae1ece72282fdfa558810e8422bb690bbc6d2193 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Thu, 16 Jul 2015 15:25:14 -0500 Subject: Make include_module_at static Since I can't forsee any reason to use it directly inplace of using prepend/include --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index f342ded20..90c463579 100644 --- a/src/class.c +++ b/src/class.c @@ -797,7 +797,7 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) return ic; } -MRB_API int +static int include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) { struct RClass *p, *ic; -- cgit v1.2.3 From 26bee4a16b5763b407a842bd1697389961600d68 Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Thu, 16 Jul 2015 15:25:27 -0500 Subject: Added mrb_prepend_module to mruby header --- include/mruby.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mruby.h b/include/mruby.h index 1b792ce90..b4ec13fdc 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -206,6 +206,7 @@ MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass* MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); MRB_API mrb_value mrb_singleton_class(mrb_state*, mrb_value); MRB_API void mrb_include_module(mrb_state*, struct RClass*, struct RClass*); +MRB_API void mrb_prepend_module(mrb_state*, struct RClass*, struct RClass*); MRB_API void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); MRB_API void mrb_define_class_method(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); -- cgit v1.2.3 From 08c12ab7bffaa1b96a3e4f9eee34e155eeec9310 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Thu, 16 Jul 2015 15:33:07 -0700 Subject: Don't crash if pattern not found for sub --- mrblib/string.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/mrblib/string.rb b/mrblib/string.rb index ee097ad6d..23cf02e97 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -111,6 +111,7 @@ class String def sub(*args, &block) if args.size == 2 pre, post = split(args[0], 2) + return self unless post # The sub target wasn't found in the string pre + args[1].__sub_replace(pre, args[0], post) + post elsif args.size == 1 && block split(args[0], 2).join(block.call(args[0])) -- cgit v1.2.3 From 78a40fce8881247419955291f34ca36eb0549126 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 17 Jul 2015 14:21:13 -0400 Subject: Update hash.h.md --- doc/api/mruby/hash.h.md | 272 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md index 1d713d59e..bdc2a7f2b 100644 --- a/doc/api/mruby/hash.h.md +++ b/doc/api/mruby/hash.h.md @@ -47,6 +47,17 @@ Example_Class.new ### mrb_hash_set +```C +void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val); +``` + +Sets a keys and values to hashes. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example sets a key and value pair to a hash. In pure Ruby doing this is equivalent to a = {:da_key => 80}. + + ```C #include #include @@ -93,4 +104,265 @@ After compiling you should get these results. Hash ``` +### mrb_hash_get + +```C +mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); +``` + +Gets a value from a key. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example gets a value from a key. In pure Ruby doing this is equivalent to a = {:da_key => 80} +a[:da_key]. + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_value; // Declare variable for getting a value from a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + get_hash_value = mrb_hash_get(mrb, new_hash, mrb_symbol_value(hash_key_b)); // Get value from hash. + mrb_funcall(mrb, obj, "method_name", 1, get_hash_value); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +#### Result + +After compiling you should get these results. + +```Ruby +90 +Fixnum +``` + +### mrb_hash_delete_key + +```C +mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key); +``` + +Deletes hash key and value pair. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example deletes hash key and value pair. In pure Ruby doing this is equivalent to a = {:da_key1 => 80,:da_key2 => 90} +a.delete(:da_key2) + + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_value; // Declare variable for getting a value from a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + mrb_hash_delete_key(mrb, new_hash, mrb_symbol_value(hash_key_b)); + mrb_funcall(mrb, obj, "another_method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +```Ruby +class Example_Class + def method_name(a) + puts "Hash pre deletion #{a}" + #puts a.class + end + # Show deleted key and value pair. + def another_method_name(a) + puts "Hash post deletion #{a}" + end +end +Example_Class.new +``` + +#### Result +After compiling you should get these results. + +```Ruby +Hash pre deletion {:da_key1 => 80, :da_key2 => 90} +Hash post deletion {:da_key1 => 80} +``` + +### mrb_hash_keys + +```C +mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); +``` + +Gets an array of keys. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example gets an array of keys from a hash. + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_keys; // Declare variable for getting an array of keys. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + get_hash_keys = mrb_hash_keys(mrb, new_hash); // get an array of keys. + mrb_funcall(mrb, obj, "method_name", 1, get_hash_keys); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +```Ruby +class Example_Class + def method_name(a) + puts a + puts a.class + end +end +Example_Class.new +``` + +#### Result + +After compiling you should get these results. + +```Ruby +[:da_key1, :da_key2] +Array +``` + +### mrb_hash_clear + +```C +mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +``` + +Clears the hash. +#### Example + +In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument +and what class the passed in value is. This example clears the hash. In pure Ruby doing this is equivalent to +a = {:da_key1 => 80,:da_key2 => 90} +a.clear + +```C +#include +#include +#include "mruby/hash.h" // Needs the hash header. +#include "mruby/compile.h" + +int main(int argc, char *argv[]) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash; // Declare variable for getting a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + get_hash = mrb_hash_clear(mrb, new_hash); + mrb_funcall(mrb, obj, "another_method_name", 1, get_hash); + fclose(fp); + mrb_close(mrb); + return 0; +} +``` + +#### test_ext.rb + +```Ruby +class Example_Class + def method_name(a) + puts "Hash pre clear #{a}" + #puts a.class + end + # Show clear hash. + def another_method_name(a) + puts "Hash post clear #{a}" + end +end +Example_Class.new +``` + +#### Result + +After compiling you should get these results. + +```Ruby +Hash pre clear {:da_key1 => 80, :da_key2 => 90} +Hash post clear {} +``` -- cgit v1.2.3 From f282d947933b81a4c93f2cccf0313c3431458b51 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Fri, 17 Jul 2015 14:25:15 -0400 Subject: Update hash.h.md --- doc/api/mruby/hash.h.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md index bdc2a7f2b..b7962696c 100644 --- a/doc/api/mruby/hash.h.md +++ b/doc/api/mruby/hash.h.md @@ -55,8 +55,11 @@ Sets a keys and values to hashes. #### Example In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. This example sets a key and value pair to a hash. In pure Ruby doing this is equivalent to a = {:da_key => 80}. +and what class the passed in value is. This example sets a key and value pair to a hash. In pure Ruby doing this is equivalent to: +```Ruby +a = {:da_key => 80} +``` ```C #include @@ -114,8 +117,12 @@ Gets a value from a key. #### Example In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. This example gets a value from a key. In pure Ruby doing this is equivalent to a = {:da_key => 80} -a[:da_key]. +and what class the passed in value is. This example gets a value from a key. In pure Ruby doing this is equivalent to: + +```Ruby +a = {:da_key => 80} +a[:da_key] +``` ```C #include @@ -177,9 +184,12 @@ Deletes hash key and value pair. #### Example In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. This example deletes hash key and value pair. In pure Ruby doing this is equivalent to a = {:da_key1 => 80,:da_key2 => 90} -a.delete(:da_key2) +and what class the passed in value is. This example deletes hash key and value pair. In pure Ruby doing this is equivalent to: +```Ruby +a = {:da_key1 => 80,:da_key2 => 90} +a.delete(:da_key2) +``` ```C #include @@ -308,9 +318,12 @@ Clears the hash. #### Example In this example we read from a Ruby file inside C. The Ruby code will print what you pass as an argument -and what class the passed in value is. This example clears the hash. In pure Ruby doing this is equivalent to +and what class the passed in value is. This example clears the hash. In pure Ruby doing this is equivalent to: + +```Ruby a = {:da_key1 => 80,:da_key2 => 90} a.clear +``` ```C #include -- cgit v1.2.3 From 6619dc4d75126d98f77e0989d542a079982639b3 Mon Sep 17 00:00:00 2001 From: "Ralph Desir(Mav7)" Date: Fri, 17 Jul 2015 14:43:55 -0400 Subject: Deleted range and string markdowns for now. --- doc/api/mruby/range.h.md | 0 doc/api/mruby/string.h.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/api/mruby/range.h.md delete mode 100644 doc/api/mruby/string.h.md diff --git a/doc/api/mruby/range.h.md b/doc/api/mruby/range.h.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From 18a0900a8241575795838f6b803208dfb7bfa0b1 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Sun, 19 Jul 2015 22:34:48 +0900 Subject: Fix indents; Indent is two spaces; Delete tabs [skip ci] --- doc/api/mruby/array.h.md | 223 +++++++++++++++++++------------------- doc/api/mruby/hash.h.md | 273 +++++++++++++++++++++++------------------------ doc/api/mruby/value.h.md | 40 +++---- 3 files changed, 267 insertions(+), 269 deletions(-) diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md index e1fb0003d..36c253cec 100644 --- a/doc/api/mruby/array.h.md +++ b/doc/api/mruby/array.h.md @@ -12,28 +12,27 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/array.h" // Needs the array header. #include "mruby/compile.h" - int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_value new_ary; // Declare variable. + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; } ``` test.rb ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -52,32 +51,32 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; } ``` test.rb ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -103,37 +102,37 @@ called pop_ary that will return the array alone(just to be clean) and you should #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_ary); - mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60. - mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results. - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_ary); + mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60. + mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results. + fclose(fp); + mrb_close(mrb); + return 0; } ``` test.rb ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end - def pop_ary(a) - puts a - end + def method_name(a) + puts a + puts a.class + end + def pop_ary(a) + puts a + end end Example_Class.new ``` @@ -158,35 +157,35 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_value ary_ref; // Declare variable. - mrb_value new_ary; // Declare variable. - mrb_int random_value1 = 70; // Initialize variable - mrb_int random_value2 = 60; // Initialize variable - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); // Initialize ruby array. - /* Pushes the fixnum value from random_value1 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - /* Pushes the fixnum value from random_value2 to the new_ary instance. */ - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1. - mrb_value obj = mrb_load_file(mrb,fp); - /* Passing the value from ary_ref to the method method_name.*/ - mrb_funcall(mrb, obj, "method_name", 1, ary_ref); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_value ary_ref; // Declare variable. + mrb_value new_ary; // Declare variable. + mrb_int random_value1 = 70; // Initialize variable + mrb_int random_value2 = 60; // Initialize variable + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); // Initialize ruby array. + /* Pushes the fixnum value from random_value1 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + /* Pushes the fixnum value from random_value2 to the new_ary instance. */ + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1. + mrb_value obj = mrb_load_file(mrb,fp); + /* Passing the value from ary_ref to the method method_name.*/ + mrb_funcall(mrb, obj, "method_name", 1, ary_ref); + fclose(fp); + mrb_close(mrb); + return 0; } ``` test.rb ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -211,36 +210,36 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_value new_ary; - mrb_value ary_obj; - mrb_int random_value1 = 70; - mrb_int random_value2 = 60; - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - FILE *fp = fopen("test.rb","r"); - new_ary = mrb_ary_new(mrb); - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); - mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); - /* Sets the fixnum value of 7 to the second index of the array.*/ - mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7)); - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "before_after", 1, new_ary); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_value new_ary; + mrb_value ary_obj; + mrb_int random_value1 = 70; + mrb_int random_value2 = 60; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + new_ary = mrb_ary_new(mrb); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1)); + mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2)); + /* Sets the fixnum value of 7 to the second index of the array.*/ + mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7)); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "before_after", 1, new_ary); + fclose(fp); + mrb_close(mrb); + return 0; } ``` test.rb ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end - def before_after(a) - puts a - end + def method_name(a) + puts a + puts a.class + end + def before_after(a) + puts a + end end Example_Class.new ``` diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md index b7962696c..fa12ea670 100644 --- a/doc/api/mruby/hash.h.md +++ b/doc/api/mruby/hash.h.md @@ -17,19 +17,18 @@ to Hash.new. #include "mruby/hash.h" // Needs the hash header. #include "mruby/compile.h" - int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_funcall(mrb, obj, "method_name", 1, new_hash); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -37,10 +36,10 @@ int main(int argc, char *argv[]) ``` Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -67,22 +66,21 @@ a = {:da_key => 80} #include "mruby/hash.h" // Needs the hash header. #include "mruby/compile.h" - int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable. - mrb_sym hash_key = mrb_intern_cstr(mrb, "da_key"); // Declare a symbol. - mrb_int hash_value = 80; // Declare a fixnum value. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key), mrb_fixnum_value(hash_value)); // Set values to hash. - mrb_funcall(mrb, obj, "method_name", 1, new_hash); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable. + mrb_sym hash_key = mrb_intern_cstr(mrb, "da_key"); // Declare a symbol. + mrb_int hash_value = 80; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key), mrb_fixnum_value(hash_value)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -90,10 +88,10 @@ int main(int argc, char *argv[]) ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -131,25 +129,25 @@ a[:da_key] #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable for new hash object. - mrb_value get_hash_value; // Declare variable for getting a value from a hash. - mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. - mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. - mrb_int hash_value_a = 80; // Declare a fixnum value. - mrb_int hash_value_b = 90; // Declare a fixnum value. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. - get_hash_value = mrb_hash_get(mrb, new_hash, mrb_symbol_value(hash_key_b)); // Get value from hash. - mrb_funcall(mrb, obj, "method_name", 1, get_hash_value); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_value; // Declare variable for getting a value from a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + get_hash_value = mrb_hash_get(mrb, new_hash, mrb_symbol_value(hash_key_b)); // Get value from hash. + mrb_funcall(mrb, obj, "method_name", 1, get_hash_value); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -157,10 +155,10 @@ int main(int argc, char *argv[]) ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -198,26 +196,27 @@ a.delete(:da_key2) #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable for new hash object. - mrb_value get_hash_value; // Declare variable for getting a value from a hash. - mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. - mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. - mrb_int hash_value_a = 80; // Declare a fixnum value. - mrb_int hash_value_b = 90; // Declare a fixnum value. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. - mrb_funcall(mrb, obj, "method_name", 1, new_hash); - mrb_hash_delete_key(mrb, new_hash, mrb_symbol_value(hash_key_b)); - mrb_funcall(mrb, obj, "another_method_name", 1, new_hash); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_value; // Declare variable for getting a value from a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + mrb_hash_delete_key(mrb, new_hash, mrb_symbol_value(hash_key_b)); + mrb_funcall(mrb, obj, "another_method_name", 1, new_hash); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -225,14 +224,14 @@ int main(int argc, char *argv[]) ```Ruby class Example_Class - def method_name(a) - puts "Hash pre deletion #{a}" - #puts a.class - end - # Show deleted key and value pair. - def another_method_name(a) - puts "Hash post deletion #{a}" - end + def method_name(a) + puts "Hash pre deletion #{a}" + #puts a.class + end + # Show deleted key and value pair. + def another_method_name(a) + puts "Hash post deletion #{a}" + end end Example_Class.new ``` @@ -265,25 +264,25 @@ and what class the passed in value is. This example gets an array of keys from a #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable for new hash object. - mrb_value get_hash_keys; // Declare variable for getting an array of keys. - mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. - mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. - mrb_int hash_value_a = 80; // Declare a fixnum value. - mrb_int hash_value_b = 90; // Declare a fixnum value. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. - get_hash_keys = mrb_hash_keys(mrb, new_hash); // get an array of keys. - mrb_funcall(mrb, obj, "method_name", 1, get_hash_keys); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash_keys; // Declare variable for getting an array of keys. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + get_hash_keys = mrb_hash_keys(mrb, new_hash); // get an array of keys. + mrb_funcall(mrb, obj, "method_name", 1, get_hash_keys); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -291,10 +290,10 @@ int main(int argc, char *argv[]) ```Ruby class Example_Class - def method_name(a) - puts a - puts a.class - end + def method_name(a) + puts a + puts a.class + end end Example_Class.new ``` @@ -332,26 +331,26 @@ a.clear #include "mruby/compile.h" int main(int argc, char *argv[]) -{ - mrb_state *mrb = mrb_open(); - if (!mrb) { /* handle error */ } - mrb_value new_hash; // Declare variable for new hash object. - mrb_value get_hash; // Declare variable for getting a hash. - mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. - mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. - mrb_int hash_value_a = 80; // Declare a fixnum value. - mrb_int hash_value_b = 90; // Declare a fixnum value. - FILE *fp = fopen("test_ext.rb","r"); - new_hash = mrb_hash_new(mrb); // Initialize hash. - mrb_value obj = mrb_load_file(mrb,fp); - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. - mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. - mrb_funcall(mrb, obj, "method_name", 1, new_hash); - get_hash = mrb_hash_clear(mrb, new_hash); - mrb_funcall(mrb, obj, "another_method_name", 1, get_hash); - fclose(fp); - mrb_close(mrb); - return 0; +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_value new_hash; // Declare variable for new hash object. + mrb_value get_hash; // Declare variable for getting a hash. + mrb_sym hash_key_a = mrb_intern_cstr(mrb, "da_key1"); // Declare a symbol. + mrb_sym hash_key_b = mrb_intern_cstr(mrb, "da_key2"); // Declare a symbol. + mrb_int hash_value_a = 80; // Declare a fixnum value. + mrb_int hash_value_b = 90; // Declare a fixnum value. + FILE *fp = fopen("test_ext.rb","r"); + new_hash = mrb_hash_new(mrb); // Initialize hash. + mrb_value obj = mrb_load_file(mrb,fp); + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_a), mrb_fixnum_value(hash_value_a)); // Set values to hash. + mrb_hash_set(mrb, new_hash, mrb_symbol_value(hash_key_b), mrb_fixnum_value(hash_value_b)); // Set values to hash. + mrb_funcall(mrb, obj, "method_name", 1, new_hash); + get_hash = mrb_hash_clear(mrb, new_hash); + mrb_funcall(mrb, obj, "another_method_name", 1, get_hash); + fclose(fp); + mrb_close(mrb); + return 0; } ``` @@ -359,14 +358,14 @@ int main(int argc, char *argv[]) ```Ruby class Example_Class - def method_name(a) - puts "Hash pre clear #{a}" - #puts a.class - end - # Show clear hash. - def another_method_name(a) - puts "Hash post clear #{a}" - end + def method_name(a) + puts "Hash pre clear #{a}" + #puts a.class + end + # Show clear hash. + def another_method_name(a) + puts "Hash post clear #{a}" + end end Example_Class.new ``` diff --git a/doc/api/mruby/value.h.md b/doc/api/mruby/value.h.md index f3ae2d421..fbf2dadf1 100644 --- a/doc/api/mruby/value.h.md +++ b/doc/api/mruby/value.h.md @@ -38,10 +38,10 @@ main(void) test.rb ```Ruby class My_Class - def method_name(s) - puts s - puts s.class - end + def method_name(s) + puts s + puts s.class + end end a = My_Class.new ``` @@ -86,10 +86,10 @@ main(void) test.rb ```Ruby class My_Class - def method_name(s) - puts s - puts s.class - end + def method_name(s) + puts s + puts s.class + end end a = My_Class.new ``` @@ -134,10 +134,10 @@ main(void) test.rb ```Ruby class My_Class - def method_name(s) - puts s - puts s.class - end + def method_name(s) + puts s + puts s.class + end end a = My_Class.new ``` @@ -181,10 +181,10 @@ main(void) test.rb ```Ruby class My_Class - def method_name(s) - puts s - puts s.class - end + def method_name(s) + puts s + puts s.class + end end a = My_Class.new ``` @@ -229,10 +229,10 @@ main(void) test.rb ```Ruby class My_Class - def method_name(s) - puts s - puts s.class - end + def method_name(s) + puts s + puts s.class + end end a = My_Class.new ``` -- cgit v1.2.3 From f01704477fd420839e002875e146a58a3af91c73 Mon Sep 17 00:00:00 2001 From: Seba Gamboa Date: Wed, 22 Jul 2015 21:57:20 -0300 Subject: Add ability to change compiler versions for androideabi --- tasks/toolchains/androideabi.rake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tasks/toolchains/androideabi.rake b/tasks/toolchains/androideabi.rake index 7cdb9e43a..d2d5dcec4 100644 --- a/tasks/toolchains/androideabi.rake +++ b/tasks/toolchains/androideabi.rake @@ -27,6 +27,8 @@ MRuby::Toolchain.new(:androideabi) do |conf| ANDROID_TARGET_ARCH = ENV['ANDROID_TARGET_ARCH'] || DEFAULT_ANDROID_TARGET_ARCH ANDROID_TARGET_ARCH_ABI = ENV['ANDROID_TARGET_ARCH_ABI'] || DEFAULT_ANDROID_TARGET_ARCH_ABI ANDROID_TOOLCHAIN = ENV['ANDROID_TOOLCHAIN'] || DEFAULT_ANDROID_TOOLCHAIN + GCC_VERSION = ENV['GCC_VERSION'] || GCC_VERSION + CLANG_VERSION = ENV['CLANG_VERSION'] || CLANG_VERSION case ANDROID_TARGET_ARCH.downcase when 'arch-arm', 'arm' then @@ -74,9 +76,9 @@ MRuby::Toolchain.new(:androideabi) do |conf| else # Any other architecture are not supported by Android NDK. end - path_to_toolchain += DEFAULT_GCC_VERSION + '/prebuilt/' + HOST_PLATFORM + path_to_toolchain += GCC_VERSION + '/prebuilt/' + HOST_PLATFORM else - path_to_toolchain += 'llvm-' + DEFAULT_CLANG_VERSION + '/prebuilt/' + HOST_PLATFORM + path_to_toolchain += 'llvm-' + CLANG_VERSION + '/prebuilt/' + HOST_PLATFORM end else path_to_toolchain = ANDROID_STANDALONE_TOOLCHAIN -- cgit v1.2.3 From 007d26f168689f785be9ddf97cc5293ad534a4c7 Mon Sep 17 00:00:00 2001 From: xuejianqing Date: Sat, 25 Jul 2015 18:43:27 +0800 Subject: fix android compile bug : uninitialized constant GCC_VERSION --- tasks/toolchains/androideabi.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/toolchains/androideabi.rake b/tasks/toolchains/androideabi.rake index d2d5dcec4..272e802f7 100644 --- a/tasks/toolchains/androideabi.rake +++ b/tasks/toolchains/androideabi.rake @@ -27,8 +27,8 @@ MRuby::Toolchain.new(:androideabi) do |conf| ANDROID_TARGET_ARCH = ENV['ANDROID_TARGET_ARCH'] || DEFAULT_ANDROID_TARGET_ARCH ANDROID_TARGET_ARCH_ABI = ENV['ANDROID_TARGET_ARCH_ABI'] || DEFAULT_ANDROID_TARGET_ARCH_ABI ANDROID_TOOLCHAIN = ENV['ANDROID_TOOLCHAIN'] || DEFAULT_ANDROID_TOOLCHAIN - GCC_VERSION = ENV['GCC_VERSION'] || GCC_VERSION - CLANG_VERSION = ENV['CLANG_VERSION'] || CLANG_VERSION + GCC_VERSION = ENV['GCC_VERSION'] || DEFAULT_GCC_VERSION + CLANG_VERSION = ENV['CLANG_VERSION'] || DEFAULT_CLANG_VERSION case ANDROID_TARGET_ARCH.downcase when 'arch-arm', 'arm' then -- cgit v1.2.3 From 54c853ff4aed510d777767dcefd9da5e05d6f505 Mon Sep 17 00:00:00 2001 From: xuejianqing Date: Sun, 26 Jul 2015 21:52:56 +0800 Subject: update mrbgems doc --- doc/mrbgems/README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index e0c60daf2..f75231f71 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -198,17 +198,21 @@ end In case your GEM has more complex build requirements you can use the following options additionally inside of your GEM specification: -* `spec.cflags` (C compiler flags) -* `spec.mruby_cflags` (global C compiler flags for everything) -* `spec.mruby_ldflags` (global linker flags for everything) -* `spec.mruby_libs` (global libraries for everything) -* `spec.mruby_includes` (global includes for everything) +* `spec.cc.flags` (C compiler flags) +* `spec.cc.defines` (C compiler defines) +* `spec.cc.include_paths` (C compiler include paths) +* `spec.linker.flags` (Linker flags) +* `spec.linker.libraries` (Linker libraries) +* `spec.linker.library_paths` (Linker additional library path) +* `spec.bins` (Generate binary file) * `spec.rbfiles` (Ruby files to compile) * `spec.objs` (Object files to compile) * `spec.test_rbfiles` (Ruby test files for integration into mrbtest) * `spec.test_objs` (Object test files for integration into mrbtest) * `spec.test_preload` (Initialization files for mrbtest) +You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker. + ### include_paths and dependency Your GEM can export include paths to another GEMs that depends on your GEM. -- cgit v1.2.3 From 578db292fd9a829d10f81cbcd274993219166f32 Mon Sep 17 00:00:00 2001 From: xuejianqing Date: Mon, 27 Jul 2015 12:22:23 +0800 Subject: mrbgem compile should be depend on mrbgem.rake --- tasks/mrbgem_spec.rake | 2 +- tasks/mruby_build_commands.rake | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index 04a9c39f0..d13e7733f 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -130,7 +130,7 @@ module MRuby end def define_gem_init_builder - file objfile("#{build_dir}/gem_init") => "#{build_dir}/gem_init.c" + file objfile("#{build_dir}/gem_init") => [ "#{build_dir}/gem_init.c", File.join(dir, "mrbgem.rake") ] file "#{build_dir}/gem_init.c" => [build.mrbcfile, __FILE__] + [rbfiles].flatten do |t| FileUtils.mkdir_p build_dir generate_gem_init("#{build_dir}/gem_init.c") diff --git a/tasks/mruby_build_commands.rake b/tasks/mruby_build_commands.rake index 4fbfaa785..f4805f46d 100644 --- a/tasks/mruby_build_commands.rake +++ b/tasks/mruby_build_commands.rake @@ -92,6 +92,8 @@ module MRuby def define_rules(build_dir, source_dir='') @out_ext = build.exts.object + gemrake = File.join(source_dir, "mrbgem.rake") + rakedep = File.exist?(gemrake) ? [ gemrake ] : [] if build_dir.include? "mrbgems/" generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(.*)#{Regexp.escape out_ext}$") @@ -104,7 +106,7 @@ module MRuby file.sub(generated_file_matcher, "#{source_dir}/\\1#{ext}") }, proc { |file| - get_dependencies(file) + get_dependencies(file) + rakedep } ] do |t| run t.name, t.prerequisites.first @@ -115,7 +117,7 @@ module MRuby file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}") }, proc { |file| - get_dependencies(file) + get_dependencies(file) + rakedep } ] do |t| run t.name, t.prerequisites.first -- cgit v1.2.3 From 923e04cf5051cde3000ee84604a2a3e14b5e655d Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Mon, 27 Jul 2015 17:16:37 -0400 Subject: Shallow clone mgem source --- tasks/mruby_build_gem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index 26990a380..f0282aee0 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -59,7 +59,7 @@ module MRuby git.run_pull mgem_list_dir, mgem_list_url if $pull_gems else FileUtils.mkdir_p mgem_list_dir - git.run_clone mgem_list_dir, mgem_list_url + git.run_clone mgem_list_dir, mgem_list_url, "--depth 1" end require 'yaml' -- cgit v1.2.3 From ca49936468a5b2f10aa743ad2363ddcf29ff96d1 Mon Sep 17 00:00:00 2001 From: cremno Date: Wed, 29 Jul 2015 20:52:32 +0200 Subject: pop cmdarg in lambda body; fix [ruby-bug#11380] regression introduced by 2fe556d9c039839c20965a2c90dff703f04e40ec --- mrbgems/mruby-compiler/core/parse.y | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b057cac17..338f6b9e3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -2154,6 +2154,7 @@ primary : literal $$ = new_lambda(p, $3, $5); local_unnest(p); p->cmdarg_stack = $4; + CMDARG_LEXPOP(); } | keyword_if expr_value then compstmt -- cgit v1.2.3 From 89ebb0c4f15db5ed0e5e6d0715bfcf4fb0a1beac Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Jul 2015 16:45:31 +0900 Subject: vm: execute ensure at the top of the fiber; fix #2903 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vm.c b/src/vm.c index 22ea177e0..765512a34 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1497,6 +1497,9 @@ RETRY_TRY_BLOCK: MRB_THROW(prev_jmp); } if (ci == mrb->c->cibase) { + while (eidx > 0) { + ecall(mrb, --eidx); + } if (ci->ridx == 0) { if (mrb->c == mrb->root_c) { regs = mrb->c->stack = mrb->c->stbase; -- cgit v1.2.3 From f0040b537136e8f36ff3a6de2508ca8c7c8974a6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Jul 2015 16:46:31 +0900 Subject: vm: execute ensure without exception at the top of the fiber; fix #2904 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 765512a34..025b487bc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1032,7 +1032,7 @@ RETRY_TRY_BLOCK: mrb_callinfo *ci = mrb->c->ci; int n, eidx = ci->eidx; - for (n=0; n ci[-1].eidx; n++) { + for (n=0; nc->cibase || eidx > ci[-1].eidx); n++) { ecall(mrb, --eidx); ARENA_RESTORE(mrb, ai); } -- cgit v1.2.3 From 52a9712c26baafe0763557eba4da0057c2b57509 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Aug 2015 16:16:22 +0900 Subject: link libncurses when there's /usr/include/curses.h; fix #2905 --- mrbgems/mruby-bin-mirb/mrbgem.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index 7d45409c9..a74871d81 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -20,6 +20,9 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| spec.linker.libraries << 'edit' else spec.linker.libraries << 'readline' + if spec.build.cc.search_header_path 'curses.h' + spec.linker.libraries << 'ncurses' + end end elsif spec.build.cc.search_header_path 'linenoise.h' spec.cc.defines << "ENABLE_LINENOISE" -- cgit v1.2.3 From 5c055d670a7c45e0d6ba201aa8ca44a4fd24ecba Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Sun, 2 Aug 2015 14:37:12 +0200 Subject: be able to source with :path for mrbgems --- tasks/mruby_build_gem.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index f0282aee0..896aeb147 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -76,6 +76,9 @@ module MRuby if params[:core] gemdir = "#{root}/mrbgems/#{params[:core]}" + elsif params[:path] + require 'pathname' + gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}" elsif params[:git] url = params[:git] gemdir = "#{gem_clone_dir}/#{url.match(/([-\w]+)(\.[-\w]+|)$/).to_a[1]}" -- cgit v1.2.3 From 95412aeb502298e58233117d6be7dc2e95912491 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 3 Aug 2015 13:24:04 +0900 Subject: better hash value from enumerables; fix #2906 --- mrblib/enum.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 6bf219283..e979fe90e 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -402,8 +402,11 @@ module Enumerable # redefine #hash 15.3.1.3.15 def hash h = 12347 + i = 0 self.each do |e| - h ^= e.hash + n = e.hash << (i % 16) + h ^= n + i += 1 end h end -- cgit v1.2.3 From 996d0c03450a6ebd9e004b0a323ed7724386ebc5 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 3 Aug 2015 19:22:46 -0400 Subject: Set language, and use the new Trusty env --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7be58c8a..b1230ede7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ -# no installation... +language: c + +sudo: 9000 install: - sudo apt-get -q install gperf -- cgit v1.2.3 From dd612950b418b607812b1ccee3a1c2b1ec2a7f46 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 3 Aug 2015 19:47:49 -0400 Subject: Update package list --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b1230ede7..95e20ef2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ language: c sudo: 9000 install: - - sudo apt-get -q install gperf + - sudo apt-get update -qq + - sudo apt-get -q install gperf env: MRUBY_CONFIG=travis_config.rb script: "./minirake all test" -- cgit v1.2.3 From fca9522af35a5ec89d783b5611d31ad455d433c0 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 3 Aug 2015 19:55:44 -0400 Subject: Build matrix of size 2 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95e20ef2a..928c28efe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: c -sudo: 9000 +matrix: + include: + - sudo: 9000 install: - sudo apt-get update -qq -- cgit v1.2.3 From e3361fbc2ad3fc10e7e06aa611542fff783fabfe Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 3 Aug 2015 20:05:15 -0400 Subject: Add OS X build to the matrix --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 928c28efe..a3978577c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,12 @@ language: c matrix: include: - - sudo: 9000 + - os: linux + sudo: 9000 + - os: osx install: - - sudo apt-get update -qq - - sudo apt-get -q install gperf + - if [ $TRAVIS_OS_NAME = 'linux' ]; then sudo apt-get update -qq; sudo apt-get -q install gperf; fi env: MRUBY_CONFIG=travis_config.rb script: "./minirake all test" -- cgit v1.2.3 From bfcc55fbf98665b33ca7110349aeb66d3ef0df1d Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 3 Aug 2015 20:34:45 -0400 Subject: Try building on Xcode 6.4 The default 6.1 was slow --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a3978577c..bcfce3984 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ matrix: - os: linux sudo: 9000 - os: osx + osx_image: xcod6.4 install: - if [ $TRAVIS_OS_NAME = 'linux' ]; then sudo apt-get update -qq; sudo apt-get -q install gperf; fi -- cgit v1.2.3 From 4fdf492219ded3a48382970e2678f04b4fc912cd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Aug 2015 11:28:41 +0900 Subject: add String#setbyte and String#byteslice to mruby-string-ext --- mrbgems/mruby-string-ext/src/string.c | 56 +++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/string.rb | 16 ++++++++++ 2 files changed, 72 insertions(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index e925a82a7..12657e129 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -3,6 +3,7 @@ #include "mruby/array.h" #include "mruby/class.h" #include "mruby/string.h" +#include "mruby/range.h" static mrb_value mrb_str_getbyte(mrb_state *mrb, mrb_value str) @@ -18,6 +19,59 @@ mrb_str_getbyte(mrb_state *mrb, mrb_value str) return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]); } +static mrb_value +mrb_str_setbyte(mrb_state *mrb, mrb_value str) +{ + mrb_int pos, byte; + long len = RSTRING_LEN(str); + + mrb_get_args(mrb, "ii", &pos, &byte); + + if (pos < -len || len <= pos) + mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); + if (pos < 0) + pos += len; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + byte &= 0xff; + RSTRING_PTR(str)[pos] = byte; + return mrb_fixnum_value((unsigned char)byte); +} + +static mrb_value +mrb_str_byteslice(mrb_state *mrb, mrb_value str) +{ + mrb_value a1; + mrb_int len; + int argc; + + argc = mrb_get_args(mrb, "o|i", &a1, &len); + if (argc == 2) { + return mrb_str_substr(mrb, str, mrb_fixnum(a1), len); + } + switch (mrb_type(a1)) { + case MRB_TT_RANGE: + { + mrb_int beg; + + len = RSTRING_LEN(str); + if (mrb_range_beg_len(mrb, a1, &beg, &len, len)) { + return mrb_str_substr(mrb, str, beg, len); + } + return mrb_nil_value(); + } + case MRB_TT_FLOAT: + a1 = mrb_fixnum_value((mrb_int)mrb_float(a1)); + /* fall through */ + case MRB_TT_FIXNUM: + return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1); + default: + mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument"); + } + /* not reached */ + return mrb_nil_value(); +} + /* * call-seq: * str.swapcase! -> str or nil @@ -375,6 +429,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "dump", mrb_str_dump, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, s, "swapcase!", mrb_str_swapcase_bang, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "swapcase", mrb_str_swapcase, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "concat", mrb_str_concat2, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 14e00428e..5e4847f05 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -13,6 +13,22 @@ assert('String#getbyte') do assert_equal bytes2[0], str2.getbyte(0) end +assert('String#setbyte') do + str1 = "hello" + h = "H".getbyte(0) + str1.setbyte(0, h) + assert_equal(h, str1.getbyte(0)) + assert_equal("Hello", str1) +end + +assert('String#byteslice') do + str1 = "hello" + assert_equal("e", str1.byteslice(1)) + assert_equal("o", str1.byteslice(-1)) + assert_equal("ell", str1.byteslice(1..3)) + assert_equal("el", str1.byteslice(1...3)) +end + assert('String#dump') do ("\1" * 100).dump # should not raise an exception - regress #1210 "\0".inspect == "\"\\000\"" and -- cgit v1.2.3 From 0c7d29dff68b4d85fbbc9c6f8c0328ddb303f000 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 7 Aug 2015 15:30:52 +0900 Subject: FIXABLE() may work wrong on MRB_INT64; fix #2909 --- src/numeric.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index b9aef51d9..14c0b76a6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -55,7 +55,8 @@ num_pow(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); yv = mrb_to_flo(mrb, y); d = pow(mrb_to_flo(mrb, x), yv); - if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0) + if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0 && + (d < 0 || (d > 0 && (mrb_int)d > 0))) return mrb_fixnum_value((mrb_int)d); return mrb_float_value(mrb, d); } -- cgit v1.2.3 From 5af770cd59f6edb6f111f497fef4df3fe956cc62 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Aug 2015 11:41:01 +0900 Subject: prevent out-of-bounds ensure clause access; fix #2910 --- src/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm.c b/src/vm.c index 025b487bc..00636a870 100644 --- a/src/vm.c +++ b/src/vm.c @@ -266,6 +266,7 @@ ecall(mrb_state *mrb, int i) mrb_value *self = mrb->c->stack; struct RObject *exc; + if (i<0) return; p = mrb->c->ensure[i]; if (!p) return; if (mrb->c->ci->eidx > i) -- cgit v1.2.3 From b34ee9a4b4cf75135ab8c6887068687bbd9f5b06 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Aug 2015 14:55:48 +0900 Subject: codegen: reserve stack region for OP_APOST; fix #2824 --- mrbgems/mruby-compiler/core/codegen.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index cefde8b7b..b128231cf 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -406,7 +406,18 @@ push_(codegen_scope *s) nregs_update; } +static void +push_n_(codegen_scope *s, size_t n) +{ + if (s->sp+n > 511) { + codegen_error(s, "too complex expression"); + } + s->sp+=n; + nregs_update; +} + #define push() push_(s) +#define push_n(n) push_n_(s,n) #define pop_(s) ((s)->sp--) #define pop() pop_(s) #define pop_n(n) (s->sp-=(n)) @@ -1001,6 +1012,8 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) else { pop(); } + push_n(post); + pop_n(post); genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); n = 1; if (t->car) { /* rest */ -- cgit v1.2.3 From dfaff83eba8fbf3953b6ab0e92df41899de2eccc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Aug 2015 15:11:00 +0900 Subject: codegen: add peep hole optimization to skip overridden OP_MOVE --- mrbgems/mruby-compiler/core/codegen.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b128231cf..ba451309e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -188,6 +188,11 @@ genop_peep(codegen_scope *s, mrb_code i, int val) if (val) break; switch (c0) { case OP_MOVE: + if (GETARG_A(i) == GETARG_A(i0)) { + /* skip overriden OP_MOVE */ + s->pc--; + return genop_peep(s, i, val); + } if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { /* skip swapping OP_MOVE */ return 0; -- cgit v1.2.3 From e4f32ad9ad96fddb5613178a848fafe5c869f7c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Aug 2015 15:19:32 +0900 Subject: codegen: don't need to genop(); just update s->iseq directly --- mrbgems/mruby-compiler/core/codegen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index ba451309e..3853814ec 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -191,7 +191,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val) if (GETARG_A(i) == GETARG_A(i0)) { /* skip overriden OP_MOVE */ s->pc--; - return genop_peep(s, i, val); + s->iseq[s->pc] = i; } if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { /* skip swapping OP_MOVE */ -- cgit v1.2.3 From 2574adab48d0995204ee45b812125b2134c6c8f3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Aug 2015 16:27:48 +0900 Subject: compiler: allow "class A end" by tweaking the superclass rule like CRuby2.3 --- mrbgems/mruby-compiler/core/parse.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 338f6b9e3..097d63ac4 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -2942,7 +2942,7 @@ backref : tNTH_REF | tBACK_REF ; -superclass : term +superclass : /* term */ { $$ = 0; } @@ -2954,12 +2954,12 @@ superclass : term expr_value term { $$ = $3; - } + } /* | error term { yyerrok; $$ = 0; - } + } */ ; f_arglist : '(' f_args rparen -- cgit v1.2.3 From 96c948d812f06c1ad1024f6db5089e47dbd58d23 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Tue, 11 Aug 2015 18:02:12 +0900 Subject: Remove non-need tmp value --- src/etc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/etc.c b/src/etc.c index a8a21e740..f5a502795 100644 --- a/src/etc.c +++ b/src/etc.c @@ -67,17 +67,15 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_value tmp; mrb_sym id; switch (mrb_type(name)) { default: - tmp = mrb_check_string_type(mrb, name); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); + name = mrb_check_string_type(mrb, name); + if (mrb_nil_p(name)) { + name = mrb_inspect(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); } - name = tmp; /* fall through */ case MRB_TT_STRING: name = mrb_str_intern(mrb, name); -- cgit v1.2.3 From c7fad5aa33f77d1869d9b879c9f8aeb5e688d64c Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Wed, 12 Aug 2015 10:20:55 +0900 Subject: Remove duplicated RARRAY_LEN check --- src/array.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/array.c b/src/array.c index 0a99040c0..2622ee528 100644 --- a/src/array.c +++ b/src/array.c @@ -19,7 +19,6 @@ static inline mrb_value ary_elt(mrb_value ary, mrb_int offset) { - if (RARRAY_LEN(ary) == 0) return mrb_nil_value(); if (offset < 0 || RARRAY_LEN(ary) <= offset) { return mrb_nil_value(); } -- cgit v1.2.3 From ad50a6c4103b6a95e25ed7eaaf99b79a220d36cf Mon Sep 17 00:00:00 2001 From: cremno Date: Wed, 29 Jul 2015 21:54:06 +0200 Subject: fix irep float dump format string for MRB_USE_FLOAT IEC 60559 single format has 6 to 9 significant decimal digits precision. However the printf conversion specifier e (and E, of course) already writes 1 digit - the one before the decimal point - and precision specifies the number of digits to write after the decimal point. --- src/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dump.c b/src/dump.c index 462e036b4..734f38043 100644 --- a/src/dump.c +++ b/src/dump.c @@ -16,7 +16,7 @@ #define FLAG_BYTEORDER_NONATIVE 0 #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.9e" +#define MRB_FLOAT_FMT "%.8e" #else #define MRB_FLOAT_FMT "%.16e" #endif -- cgit v1.2.3 From eec00ccf6074cfe5d5b7357180b58282d0dd8c66 Mon Sep 17 00:00:00 2001 From: cremno Date: Mon, 17 Aug 2015 20:51:25 +0200 Subject: delete duplicate definition of Exception.exception It overwrote the original definition in src/error.c, line 446. --- mrblib/error.rb | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/mrblib/error.rb b/mrblib/error.rb index d76dd9c56..2674af7a2 100644 --- a/mrblib/error.rb +++ b/mrblib/error.rb @@ -1,18 +1,3 @@ -## -# Exception -# -# ISO 15.2.22 -class Exception - - ## - # Raise an exception. - # - # ISO 15.2.22.4.1 - def self.exception(*args, &block) - self.new(*args, &block) - end -end - # ISO 15.2.24 class ArgumentError < StandardError end -- cgit v1.2.3 From c326f065e17b31035815bf90a7f3cbf7e605a275 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Wed, 19 Aug 2015 16:17:06 +0900 Subject: array.rb: refactor some code --- mrblib/array.rb | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index 933f822db..ef2b53725 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -16,7 +16,7 @@ class Array while idx < length and length <= self.length and length = self.length-1 elm = self[idx += 1] unless elm - if elm == nil and length >= self.length + if elm.nil? and length >= self.length break end end @@ -50,9 +50,7 @@ class Array def collect!(&block) return to_enum :collect! unless block_given? - self.each_index{|idx| - self[idx] = block.call(self[idx]) - } + self.each_index { |idx| self[idx] = block.call(self[idx]) } self end @@ -72,7 +70,7 @@ class Array self.clear if size > 0 - self[size - 1] = nil # allocate + self[size - 1] = nil # allocate idx = 0 while idx < size @@ -158,14 +156,11 @@ class Array len = self.size n = other.size - if len > n - len = n - end + len = n if len > n i = 0 while i < len n = (self[i] <=> other[i]) - return n if n == nil - return n if n != 0 + return n if n.nil? || n != 0 i += 1 end len = self.size - other.size @@ -185,7 +180,7 @@ class Array self.delete_at(i) ret = key end - if ret == nil && block + if ret.nil? && block block.call else ret -- cgit v1.2.3 From cf588bd5cb094e6ee22d8d45c2005cf0da55d197 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Thu, 20 Aug 2015 17:28:34 +0900 Subject: range.rb: refactor code (use ! instead of not, use favor modifier if and unless usage when having a single-line body) --- mrblib/range.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 64fa0cb6c..5e5fd9bdc 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -26,9 +26,7 @@ class Range return self end - unless val.respond_to? :succ - raise TypeError, "can't iterate" - end + raise TypeError, "can't iterate" unless val.respond_to? :succ return self if (val <=> last) > 0 @@ -37,18 +35,14 @@ class Range val = val.succ end - if not exclude_end? and (val <=> last) == 0 - block.call(val) - end + block.call(val) if !exclude_end? && (val <=> last) == 0 self end # redefine #hash 15.3.1.3.15 def hash h = first.hash ^ last.hash - if self.exclude_end? - h += 1 - end + h += 1 if self.exclude_end? h end end -- cgit v1.2.3 From cb870de2b52fad05c8ba0b23893008d0ba77ac3b Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Thu, 20 Aug 2015 17:33:16 +0900 Subject: numeric.rb: refactor code (Avoid using {...} for multi-line blocks, Surrounding space missing in default value assignment) --- mrblib/numeric.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index cf608b04b..206185e78 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -100,7 +100,7 @@ module Integral # Calls the given block from +self+ to +num+ # incremented by +step+ (default 1). # - def step(num, step=1, &block) + def step(num, step = 1, &block) raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block_given? @@ -165,16 +165,12 @@ class Float # floats should be compatible to integers. def >> other n = self.to_i - other.to_i.times { - n /= 2 - } + other.to_i.times { n /= 2 } n end def << other n = self.to_i - other.to_i.times { - n *= 2 - } + other.to_i.times { n *= 2 } n.to_i end end -- cgit v1.2.3 From 11524f6f678fde684941937413b6bc2cba23b630 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Thu, 20 Aug 2015 17:52:30 +0900 Subject: string.rb: refactor code (remove redundant code) --- mrblib/string.rb | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 23cf02e97..05b13cb43 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -80,12 +80,8 @@ class String # ISO 15.2.10.5.19 def gsub!(*args, &block) str = self.gsub(*args, &block) - if str != self - self.replace(str) - self - else - nil - end + return nil if str == self + self.replace(str) end ## @@ -129,12 +125,8 @@ class String # ISO 15.2.10.5.37 def sub!(*args, &block) str = self.sub(*args, &block) - if str != self - self.replace(str) - self - else - nil - end + return nil if str == self + self.replace(str) end ## @@ -165,20 +157,16 @@ class String # Modify +self+ by replacing the content of +self+ # at the position +pos+ with +value+. def []=(pos, value) - if pos < 0 - pos += self.length - end + pos += self.length if pos < 0 b = self[0, pos] - a = self[pos+1..-1] + a = self[pos + 1..-1] self.replace([b, value, a].join('')) end ## # ISO 15.2.10.5.3 def =~(re) - if re.respond_to? :to_str - raise TypeError, "type mismatch: String given" - end + raise TypeError, "type mismatch: String given" if re.respond_to? :to_str re =~ self end -- cgit v1.2.3 From 931a7223e6ec20bfc5dbb894c74e7e7d638dc538 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Thu, 20 Aug 2015 18:53:13 +0900 Subject: array.rb: refactor (use onliner code if possible) --- mrblib/array.rb | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index ef2b53725..65dd0d665 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -180,20 +180,14 @@ class Array self.delete_at(i) ret = key end - if ret.nil? && block - block.call - else - ret - end + return block.call if ret.nil? && block + ret end # internal method to convert multi-value to single value def __svalue - if self.size < 2 - self.first - else - self - end + return self.first if self.size < 2 + self end end -- cgit v1.2.3 From 85f0dd7da0fe41310883d9a65156c429135590f5 Mon Sep 17 00:00:00 2001 From: "go.kikuta" Date: Thu, 20 Aug 2015 18:53:56 +0900 Subject: enum.rb: refactor code (remove redundant code) --- mrblib/enum.rb | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index e979fe90e..f0c9a4884 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -24,17 +24,9 @@ module Enumerable # ISO 15.3.2.2.1 def all?(&block) if block - self.each{|*val| - unless block.call(*val) - return false - end - } + self.each{|*val| return false unless block.call(*val)} else - self.each{|*val| - unless val.__svalue - return false - end - } + self.each{|*val| return false unless val.__svalue} end true end @@ -49,17 +41,9 @@ module Enumerable # ISO 15.3.2.2.2 def any?(&block) if block - self.each{|*val| - if block.call(*val) - return true - end - } + self.each{|*val| return true if block.call(*val)} else - self.each{|*val| - if val.__svalue - return true - end - } + self.each{|*val| return true if val.__svalue} end false end @@ -75,9 +59,7 @@ module Enumerable return to_enum :collect unless block ary = [] - self.each{|*val| - ary.push(block.call(*val)) - } + self.each{|*val| ary.push(block.call(*val))} ary end @@ -183,9 +165,7 @@ module Enumerable # ISO 15.3.2.2.10 def include?(obj) self.each{|*val| - if val.__svalue == obj - return true - end + return true if val.__svalue == obj } false end -- cgit v1.2.3 From 0d055559f1d447b1ae694aae2ded63dbff7cd7c2 Mon Sep 17 00:00:00 2001 From: INOUE Yasuyuki Date: Sat, 22 Aug 2015 19:57:11 +0900 Subject: Use #nil? instead of == nil. --- mrbgems/mruby-array-ext/mrblib/array.rb | 24 ++++++++++++------------ mrbgems/mruby-enum-ext/mrblib/enum.rb | 6 +++--- mrbgems/mruby-string-ext/mrblib/string.rb | 12 ++++++------ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index fd80fa0bb..1f1d97376 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -217,7 +217,7 @@ class Array # [ "a", "b", "c" ].compact! #=> nil # def compact! - result = self.select { |e| e != nil } + result = self.select { |e| !e.nil? } if result.size == self.size nil else @@ -262,7 +262,7 @@ class Array # def fetch(n=nil, ifnone=NONE, &block) - warn "block supersedes default value argument" if n != nil && ifnone != NONE && block + warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block idx = n if idx < 0 @@ -312,51 +312,51 @@ class Array # def fill(arg0=nil, arg1=nil, arg2=nil, &block) - if arg0 == nil && arg1 == nil && arg2 == nil && !block + if arg0.nil? && arg1.nil? && arg2.nil? && !block raise ArgumentError, "wrong number of arguments (0 for 1..3)" end beg = len = 0 ary = [] if block - if arg0 == nil && arg1 == nil && arg2 == nil + if arg0.nil? && arg1.nil? && arg2.nil? # ary.fill { |index| block } -> ary beg = 0 len = self.size - elsif arg0 != nil && arg0.kind_of?(Range) + elsif !arg0.nil? && arg0.kind_of?(Range) # ary.fill(range) { |index| block } -> ary beg = arg0.begin beg += self.size if beg < 0 len = arg0.end len += self.size if len < 0 len += 1 unless arg0.exclude_end? - elsif arg0 != nil + elsif !arg0.nil? # ary.fill(start [, length] ) { |index| block } -> ary beg = arg0 beg += self.size if beg < 0 - if arg1 == nil + if arg1.nil? len = self.size else len = arg0 + arg1 end end else - if arg0 != nil && arg1 == nil && arg2 == nil + if !arg0.nil? && arg1.nil? && arg2.nil? # ary.fill(obj) -> ary beg = 0 len = self.size - elsif arg0 != nil && arg1 != nil && arg1.kind_of?(Range) + elsif !arg0.nil? && !arg1.nil? && arg1.kind_of?(Range) # ary.fill(obj, range ) -> ary beg = arg1.begin beg += self.size if beg < 0 len = arg1.end len += self.size if len < 0 len += 1 unless arg1.exclude_end? - elsif arg0 != nil && arg1 != nil + elsif !arg0.nil? && !arg1.nil? # ary.fill(obj, start [, length]) -> ary beg = arg1 beg += self.size if beg < 0 - if arg2 == nil + if arg2.nil? len = self.size else len = beg + arg2 @@ -582,7 +582,7 @@ class Array elsif v == true satisfied = true smaller = true - elsif v == false || v == nil + elsif v == false || v.nil? smaller = false end if smaller diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index f6629ed79..6fef0c077 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -515,7 +515,7 @@ module Enumerable # def each_with_object(obj=nil, &block) - raise ArgumentError, "wrong number of arguments (0 for 1)" if obj == nil + raise ArgumentError, "wrong number of arguments (0 for 1)" if obj.nil? return to_enum(:each_with_object, obj) unless block @@ -574,10 +574,10 @@ module Enumerable # def cycle(n=nil, &block) - return to_enum(:cycle, n) if !block && n == nil + return to_enum(:cycle, n) if !block && n.nil? ary = [] - if n == nil + if n.nil? self.each do|*val| ary.push val block.call(*val) diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 2b61fdb48..7d9bc00b9 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -164,9 +164,9 @@ class String # string #=> "thsa sting" # def slice!(arg1, arg2=nil) - raise "wrong number of arguments (for 1..2)" if arg1 == nil && arg2 == nil + raise "wrong number of arguments (for 1..2)" if arg1.nil? && arg2.nil? - if arg1 != nil && arg2 != nil + if !arg1.nil? && !arg2.nil? idx = arg1 idx += self.size if arg1 < 0 if idx >= 0 && idx <= self.size && arg2 > 0 @@ -196,8 +196,8 @@ class String return nil end end - unless str == nil || str == "" - if arg1 != nil && arg2 !=nil + unless str.nil? || str == "" + if !arg1.nil? && !arg2.nil? idx = arg1 >= 0 ? arg1 : self.size+arg1 str2 = self[0...idx] + self[idx+arg2..-1].to_s else @@ -207,13 +207,13 @@ class String str2 = self[0...idx] + self[idx2+1..-1].to_s elsif arg1.kind_of?(String) idx = self.index(arg1) - str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx == nil + str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx.nil? else idx = arg1 >= 0 ? arg1 : self.size+arg1 str2 = self[0...idx] + self[idx+1..-1].to_s end end - self.replace(str2) unless str2 == nil + self.replace(str2) unless str2.nil? end str end -- cgit v1.2.3 From 383a7d24d369bbd0e8813d7aabc587fb769e9d9c Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Sat, 22 Aug 2015 10:18:12 -0400 Subject: Move test source code and rake task to mrbgem --- mrbgems/mruby-test/README.md | 7 ++ mrbgems/mruby-test/driver.c | 166 ++++++++++++++++++++++++++++++++++++++ mrbgems/mruby-test/init_mrbtest.c | 40 +++++++++ mrbgems/mruby-test/mrbgem.rake | 69 ++++++++++++++++ test/README.md | 7 -- test/driver.c | 166 -------------------------------------- test/init_mrbtest.c | 40 --------- test/mrbtest.rake | 69 ---------------- 8 files changed, 282 insertions(+), 282 deletions(-) create mode 100644 mrbgems/mruby-test/README.md create mode 100644 mrbgems/mruby-test/driver.c create mode 100644 mrbgems/mruby-test/init_mrbtest.c create mode 100644 mrbgems/mruby-test/mrbgem.rake delete mode 100644 test/README.md delete mode 100644 test/driver.c delete mode 100644 test/init_mrbtest.c delete mode 100644 test/mrbtest.rake diff --git a/mrbgems/mruby-test/README.md b/mrbgems/mruby-test/README.md new file mode 100644 index 000000000..fa4b91e3a --- /dev/null +++ b/mrbgems/mruby-test/README.md @@ -0,0 +1,7 @@ +Running Tests +============= + +To run the tests, execute the following from the project's root directory. + + $ make test + diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c new file mode 100644 index 000000000..7f0633723 --- /dev/null +++ b/mrbgems/mruby-test/driver.c @@ -0,0 +1,166 @@ +/* +** mrbtest - Test for Embeddable Ruby +** +** This program runs Ruby test programs in test/t directory +** against the current mruby implementation. +*/ + + +#include +#include +#include + +#include "mruby.h" +#include "mruby/proc.h" +#include "mruby/data.h" +#include "mruby/compile.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include "mruby/array.h" + +void +mrb_init_mrbtest(mrb_state *); + +/* Print a short remark for the user */ +static void +print_hint(void) +{ + printf("mrbtest - Embeddable Ruby Test\n\n"); +} + +static int +check_error(mrb_state *mrb) +{ + /* Error check */ + /* $ko_test and $kill_test should be 0 */ + mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test")); + mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test")); + + return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0; +} + +static int +eval_test(mrb_state *mrb) +{ + /* evaluate the test */ + mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); + /* did an exception occur? */ + if (mrb->exc) { + mrb_print_error(mrb); + mrb->exc = 0; + return EXIT_FAILURE; + } + else if (!check_error(mrb)) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static void +t_printstr(mrb_state *mrb, mrb_value obj) +{ + char *s; + int len; + + if (mrb_string_p(obj)) { + s = RSTRING_PTR(obj); + len = RSTRING_LEN(obj); + fwrite(s, len, 1, stdout); + } +} + +mrb_value +mrb_t_printstr(mrb_state *mrb, mrb_value self) +{ + mrb_value argv; + + mrb_get_args(mrb, "o", &argv); + t_printstr(mrb, argv); + + return argv; +} + +void +mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) +{ + struct RClass *krn, *mrbtest; + + krn = mrb->kernel_module; + mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1)); + + mrbtest = mrb_define_module(mrb, "Mrbtest"); + + mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX)); + mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN)); + mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT)); + + if (verbose) { + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); + } +} + +void +mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) +{ + mrb_value res_src; + + if (mrb_src->exc) { + mrb_print_error(mrb_src); + exit(EXIT_FAILURE); + } + +#define TEST_COUNT_PASS(name) \ + do { \ + res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$" #name)); \ + if (mrb_fixnum_p(res_src)) { \ + mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name)); \ + mrb_gv_set(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name), mrb_fixnum_value(mrb_fixnum(res_dst) + mrb_fixnum(res_src))); \ + } \ + } while (FALSE) \ + + TEST_COUNT_PASS(ok_test); + TEST_COUNT_PASS(ko_test); + TEST_COUNT_PASS(kill_test); + +#undef TEST_COUNT_PASS + + res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$asserts")); + + if (mrb_array_p(res_src)) { + mrb_int i; + mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$asserts")); + for (i = 0; i < RARRAY_LEN(res_src); ++i) { + mrb_value val_src = RARRAY_PTR(res_src)[i]; + mrb_ary_push(mrb_dst, res_dst, mrb_str_new(mrb_dst, RSTRING_PTR(val_src), RSTRING_LEN(val_src))); + } + } +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb; + int ret; + mrb_bool verbose = FALSE; + + print_hint(); + + /* new interpreter instance */ + mrb = mrb_open(); + if (mrb == NULL) { + fprintf(stderr, "Invalid mrb_state, exiting test driver"); + return EXIT_FAILURE; + } + + if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'v') { + printf("verbose mode: enable\n\n"); + verbose = TRUE; + } + + mrb_init_test_driver(mrb, verbose); + mrb_init_mrbtest(mrb); + ret = eval_test(mrb); + mrb_close(mrb); + + return ret; +} diff --git a/mrbgems/mruby-test/init_mrbtest.c b/mrbgems/mruby-test/init_mrbtest.c new file mode 100644 index 000000000..1e2ba92bd --- /dev/null +++ b/mrbgems/mruby-test/init_mrbtest.c @@ -0,0 +1,40 @@ +#include +#include "mruby.h" +#include "mruby/irep.h" +#include "mruby/variable.h" + +extern const uint8_t mrbtest_assert_irep[]; +extern const uint8_t mrbtest_irep[]; + +void mrbgemtest_init(mrb_state* mrb); +void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose); +void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src); + +void +mrb_init_mrbtest(mrb_state *mrb) +{ + mrb_state *core_test; + + mrb_load_irep(mrb, mrbtest_assert_irep); + + core_test = mrb_open_core(mrb_default_allocf, NULL); + if (core_test == NULL) { + fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__); + exit(EXIT_FAILURE); + } + mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose")))); + mrb_load_irep(core_test, mrbtest_assert_irep); + mrb_load_irep(core_test, mrbtest_irep); + mrb_t_pass_result(mrb, core_test); + +#ifndef DISABLE_GEMS + mrbgemtest_init(mrb); +#endif + + if (mrb->exc) { + mrb_print_error(mrb); + exit(EXIT_FAILURE); + } + mrb_close(core_test); +} + diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake new file mode 100644 index 000000000..b9616fe9d --- /dev/null +++ b/mrbgems/mruby-test/mrbgem.rake @@ -0,0 +1,69 @@ +MRuby.each_target do + current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) + relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) + current_build_dir = "#{build_dir}/#{relative_from_root}" + + exec = exefile("#{current_build_dir}/mrbtest") + clib = "#{current_build_dir}/mrbtest.c" + mlib = clib.ext(exts.object) + mrbs = Dir.glob("#{current_dir}/t/*.rb") + init = "#{current_dir}/init_mrbtest.c" + ass_c = "#{current_build_dir}/assert.c" + ass_lib = ass_c.ext(exts.object) + + mrbtest_lib = libfile("#{current_build_dir}/mrbtest") + mrbtest_objs = [mlib, ass_lib] + gems.each do |v| + mrbtest_objs.concat v.test_objs + end + file mrbtest_lib => mrbtest_objs do |t| + archiver.run t.name, t.prerequisites + end + + unless build_mrbtest_lib_only? + driver_obj = objfile("#{current_build_dir}/driver") + file exec => [driver_obj, mrbtest_lib, libfile("#{build_dir}/lib/libmruby")] do |t| + gem_flags = gems.map { |g| g.linker.flags } + gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } + gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } + gem_libraries = gems.map { |g| g.linker.libraries } + gem_library_paths = gems.map { |g| g.linker.library_paths } + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries + end + end + + file ass_lib => ass_c + file ass_c => ["#{current_dir}/assert.rb", __FILE__] do |t| + FileUtils.mkdir_p File.dirname t.name + open(t.name, 'w') do |f| + mrbc.run f, [t.prerequisites.first], 'mrbtest_assert_irep' + end + end + + file mlib => clib + file clib => [mrbcfile, init, __FILE__] + mrbs do |t| + _pp "GEN", "*.rb", "#{clib.relative_path}" + FileUtils.mkdir_p File.dirname(clib) + open(clib, 'w') do |f| + f.puts %Q[/*] + f.puts %Q[ * This file contains a list of all] + f.puts %Q[ * test functions.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + f.puts %Q[] + f.puts IO.read(init) + mrbc.run f, mrbs, 'mrbtest_irep' + gems.each do |g| + f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] + end + f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] + gems.each do |g| + f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] + end + f.puts %Q[}] + end + end +end diff --git a/test/README.md b/test/README.md deleted file mode 100644 index fa4b91e3a..000000000 --- a/test/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Running Tests -============= - -To run the tests, execute the following from the project's root directory. - - $ make test - diff --git a/test/driver.c b/test/driver.c deleted file mode 100644 index 7f0633723..000000000 --- a/test/driver.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -** mrbtest - Test for Embeddable Ruby -** -** This program runs Ruby test programs in test/t directory -** against the current mruby implementation. -*/ - - -#include -#include -#include - -#include "mruby.h" -#include "mruby/proc.h" -#include "mruby/data.h" -#include "mruby/compile.h" -#include "mruby/string.h" -#include "mruby/variable.h" -#include "mruby/array.h" - -void -mrb_init_mrbtest(mrb_state *); - -/* Print a short remark for the user */ -static void -print_hint(void) -{ - printf("mrbtest - Embeddable Ruby Test\n\n"); -} - -static int -check_error(mrb_state *mrb) -{ - /* Error check */ - /* $ko_test and $kill_test should be 0 */ - mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test")); - mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test")); - - return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0; -} - -static int -eval_test(mrb_state *mrb) -{ - /* evaluate the test */ - mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); - /* did an exception occur? */ - if (mrb->exc) { - mrb_print_error(mrb); - mrb->exc = 0; - return EXIT_FAILURE; - } - else if (!check_error(mrb)) { - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -static void -t_printstr(mrb_state *mrb, mrb_value obj) -{ - char *s; - int len; - - if (mrb_string_p(obj)) { - s = RSTRING_PTR(obj); - len = RSTRING_LEN(obj); - fwrite(s, len, 1, stdout); - } -} - -mrb_value -mrb_t_printstr(mrb_state *mrb, mrb_value self) -{ - mrb_value argv; - - mrb_get_args(mrb, "o", &argv); - t_printstr(mrb, argv); - - return argv; -} - -void -mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) -{ - struct RClass *krn, *mrbtest; - - krn = mrb->kernel_module; - mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1)); - - mrbtest = mrb_define_module(mrb, "Mrbtest"); - - mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX)); - mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN)); - mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT)); - - if (verbose) { - mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); - } -} - -void -mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) -{ - mrb_value res_src; - - if (mrb_src->exc) { - mrb_print_error(mrb_src); - exit(EXIT_FAILURE); - } - -#define TEST_COUNT_PASS(name) \ - do { \ - res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$" #name)); \ - if (mrb_fixnum_p(res_src)) { \ - mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name)); \ - mrb_gv_set(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name), mrb_fixnum_value(mrb_fixnum(res_dst) + mrb_fixnum(res_src))); \ - } \ - } while (FALSE) \ - - TEST_COUNT_PASS(ok_test); - TEST_COUNT_PASS(ko_test); - TEST_COUNT_PASS(kill_test); - -#undef TEST_COUNT_PASS - - res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$asserts")); - - if (mrb_array_p(res_src)) { - mrb_int i; - mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$asserts")); - for (i = 0; i < RARRAY_LEN(res_src); ++i) { - mrb_value val_src = RARRAY_PTR(res_src)[i]; - mrb_ary_push(mrb_dst, res_dst, mrb_str_new(mrb_dst, RSTRING_PTR(val_src), RSTRING_LEN(val_src))); - } - } -} - -int -main(int argc, char **argv) -{ - mrb_state *mrb; - int ret; - mrb_bool verbose = FALSE; - - print_hint(); - - /* new interpreter instance */ - mrb = mrb_open(); - if (mrb == NULL) { - fprintf(stderr, "Invalid mrb_state, exiting test driver"); - return EXIT_FAILURE; - } - - if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'v') { - printf("verbose mode: enable\n\n"); - verbose = TRUE; - } - - mrb_init_test_driver(mrb, verbose); - mrb_init_mrbtest(mrb); - ret = eval_test(mrb); - mrb_close(mrb); - - return ret; -} diff --git a/test/init_mrbtest.c b/test/init_mrbtest.c deleted file mode 100644 index 1e2ba92bd..000000000 --- a/test/init_mrbtest.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "mruby.h" -#include "mruby/irep.h" -#include "mruby/variable.h" - -extern const uint8_t mrbtest_assert_irep[]; -extern const uint8_t mrbtest_irep[]; - -void mrbgemtest_init(mrb_state* mrb); -void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose); -void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src); - -void -mrb_init_mrbtest(mrb_state *mrb) -{ - mrb_state *core_test; - - mrb_load_irep(mrb, mrbtest_assert_irep); - - core_test = mrb_open_core(mrb_default_allocf, NULL); - if (core_test == NULL) { - fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__); - exit(EXIT_FAILURE); - } - mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose")))); - mrb_load_irep(core_test, mrbtest_assert_irep); - mrb_load_irep(core_test, mrbtest_irep); - mrb_t_pass_result(mrb, core_test); - -#ifndef DISABLE_GEMS - mrbgemtest_init(mrb); -#endif - - if (mrb->exc) { - mrb_print_error(mrb); - exit(EXIT_FAILURE); - } - mrb_close(core_test); -} - diff --git a/test/mrbtest.rake b/test/mrbtest.rake deleted file mode 100644 index b9616fe9d..000000000 --- a/test/mrbtest.rake +++ /dev/null @@ -1,69 +0,0 @@ -MRuby.each_target do - current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) - relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) - current_build_dir = "#{build_dir}/#{relative_from_root}" - - exec = exefile("#{current_build_dir}/mrbtest") - clib = "#{current_build_dir}/mrbtest.c" - mlib = clib.ext(exts.object) - mrbs = Dir.glob("#{current_dir}/t/*.rb") - init = "#{current_dir}/init_mrbtest.c" - ass_c = "#{current_build_dir}/assert.c" - ass_lib = ass_c.ext(exts.object) - - mrbtest_lib = libfile("#{current_build_dir}/mrbtest") - mrbtest_objs = [mlib, ass_lib] - gems.each do |v| - mrbtest_objs.concat v.test_objs - end - file mrbtest_lib => mrbtest_objs do |t| - archiver.run t.name, t.prerequisites - end - - unless build_mrbtest_lib_only? - driver_obj = objfile("#{current_build_dir}/driver") - file exec => [driver_obj, mrbtest_lib, libfile("#{build_dir}/lib/libmruby")] do |t| - gem_flags = gems.map { |g| g.linker.flags } - gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } - gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } - gem_libraries = gems.map { |g| g.linker.libraries } - gem_library_paths = gems.map { |g| g.linker.library_paths } - linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries - end - end - - file ass_lib => ass_c - file ass_c => ["#{current_dir}/assert.rb", __FILE__] do |t| - FileUtils.mkdir_p File.dirname t.name - open(t.name, 'w') do |f| - mrbc.run f, [t.prerequisites.first], 'mrbtest_assert_irep' - end - end - - file mlib => clib - file clib => [mrbcfile, init, __FILE__] + mrbs do |t| - _pp "GEN", "*.rb", "#{clib.relative_path}" - FileUtils.mkdir_p File.dirname(clib) - open(clib, 'w') do |f| - f.puts %Q[/*] - f.puts %Q[ * This file contains a list of all] - f.puts %Q[ * test functions.] - f.puts %Q[ *] - f.puts %Q[ * IMPORTANT:] - f.puts %Q[ * This file was generated!] - f.puts %Q[ * All manual changes will get lost.] - f.puts %Q[ */] - f.puts %Q[] - f.puts IO.read(init) - mrbc.run f, mrbs, 'mrbtest_irep' - gems.each do |g| - f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] - end - f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] - gems.each do |g| - f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] - end - f.puts %Q[}] - end - end -end -- cgit v1.2.3 From c7d0f8ebcbcd21fbe624bfd1e9b43a8037703a6d Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Sat, 22 Aug 2015 10:20:15 -0400 Subject: Refactor test/mrbtest.rake and tasks/mrbgems_test.rake into mrbgem.rake --- mrbgems/mruby-test/mrbgem.rake | 175 ++++++++++++++++++++++++++++++++--------- 1 file changed, 140 insertions(+), 35 deletions(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index b9616fe9d..8370f4713 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -1,47 +1,152 @@ -MRuby.each_target do - current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) - relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) - current_build_dir = "#{build_dir}/#{relative_from_root}" +MRuby::Gem::Specification.new('mruby-test') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby test' - exec = exefile("#{current_build_dir}/mrbtest") - clib = "#{current_build_dir}/mrbtest.c" + build.bins << 'mrbtest' + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') + + clib = "#{build_dir}/mrbtest.c" mlib = clib.ext(exts.object) - mrbs = Dir.glob("#{current_dir}/t/*.rb") - init = "#{current_dir}/init_mrbtest.c" - ass_c = "#{current_build_dir}/assert.c" - ass_lib = ass_c.ext(exts.object) - - mrbtest_lib = libfile("#{current_build_dir}/mrbtest") - mrbtest_objs = [mlib, ass_lib] - gems.each do |v| - mrbtest_objs.concat v.test_objs - end - file mrbtest_lib => mrbtest_objs do |t| - archiver.run t.name, t.prerequisites + mrbs = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb") + exec = exefile("#{build.build_dir}/bin/mrbtest") + + libmruby = libfile("#{build.build_dir}/lib/libmruby") + libmruby_core = libfile("#{build.build_dir}/lib/libmruby_core") + + mrbtest_lib = libfile("#{build_dir}/mrbtest") + mrbtest_objs = [] + + driver_obj = objfile("#{build_dir}/driver") + driver = "#{spec.dir}/driver.c" + + assert_c = "#{build_dir}/assert.c" + assert_rb = "#{MRUBY_ROOT}/test/assert.rb" + assert_lib = assert_c.ext(exts.object) + mrbtest_objs << assert_lib + + file assert_lib => assert_c + file assert_c => [build.mrbcfile, assert_rb] do |t| + open(t.name, 'w') do |f| + mrbc.run f, assert_rb, 'mrbtest_assert_irep' + end end - unless build_mrbtest_lib_only? - driver_obj = objfile("#{current_build_dir}/driver") - file exec => [driver_obj, mrbtest_lib, libfile("#{build_dir}/lib/libmruby")] do |t| - gem_flags = gems.map { |g| g.linker.flags } - gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } - gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } - gem_libraries = gems.map { |g| g.linker.libraries } - gem_library_paths = gems.map { |g| g.linker.library_paths } - linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries + gem_table = build.gems.generate_gem_table self + + build.gems.each do |g| + test_rbobj = g.test_rbireps.ext(exts.object) + g.test_objs << test_rbobj + dep_list = build.gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) + + file test_rbobj => g.test_rbireps + file g.test_rbireps => [g.test_rbfiles].flatten + [File.join(g.dir, 'mrbgem.rake'), g.build.mrbcfile, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t| + FileUtils.mkdir_p File.dirname(t.name) + open(t.name, 'w') do |f| + g.print_gem_test_header(f) + test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| + File.expand_path(g.test_preload, dir) + }.find {|file| File.exist?(file) } + + f.puts %Q[/*] + f.puts %Q[ * This file contains a test code for #{g.name} gem.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + if test_preload.nil? + f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] + else + g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" + end + g.test_rbfiles.flatten.each_with_index do |rbfile, i| + g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" + end + f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty? + dep_list.each do |d| + f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb_state *mrb);] + f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_final(mrb_state *mrb);] + end + f.puts %Q[void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose);] + f.puts %Q[void mrb_t_pass_result(mrb_state *dst, mrb_state *src);] + f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] + unless g.test_rbfiles.empty? + f.puts %Q[ mrb_state *mrb2;] + unless g.test_args.empty? + f.puts %Q[ mrb_value test_args_hash;] + end + f.puts %Q[ int ai;] + g.test_rbfiles.count.times do |i| + f.puts %Q[ ai = mrb_gc_arena_save(mrb);] + f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);] + f.puts %Q[ if (mrb2 == NULL) {] + f.puts %Q[ fprintf(stderr, "Invalid mrb_state, exiting \%s", __FUNCTION__);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] + dep_list.each do |d| + f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);] + f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);] + end + f.puts %Q[ mrb_init_test_driver(mrb2, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));] + if test_preload.nil? + f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] + else + f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] + end + f.puts %Q[ if (mrb2->exc) {] + f.puts %Q[ mrb_print_error(mrb2);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] + + unless g.test_args.empty? + f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ] + g.test_args.each do |arg_name, arg_value| + escaped_arg_name = arg_name.gsub('\\', '\\\\\\\\').gsub('"', '\"') + escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"') + f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ] + end + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "TEST_ARGS"), test_args_hash); ] + end + + f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] if g.custom_test_init? + + f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});] + f.puts %Q[ ] + + f.puts %Q[ mrb_t_pass_result(mrb, mrb2);] + f.puts %Q[ mrb_close(mrb2);] + f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] + end + end + f.puts %Q[}] + end end end - file ass_lib => ass_c - file ass_c => ["#{current_dir}/assert.rb", __FILE__] do |t| - FileUtils.mkdir_p File.dirname t.name - open(t.name, 'w') do |f| - mrbc.run f, [t.prerequisites.first], 'mrbtest_assert_irep' + build.gems.each do |v| + mrbtest_objs.concat v.test_objs + end + + file mrbtest_lib => mrbtest_objs do |t| + build.archiver.run t.name, t.prerequisites + end + + unless build.build_mrbtest_lib_only? + file exec => [driver_obj, mlib, mrbtest_lib, libmruby_core, libmruby] do |t| + gem_flags = build.gems.map { |g| g.linker.flags } + gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } + gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } + gem_libraries = build.gems.map { |g| g.linker.libraries } + gem_library_paths = build.gems.map { |g| g.linker.library_paths } + build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries end end + init = "#{spec.dir}/init_mrbtest.c" file mlib => clib - file clib => [mrbcfile, init, __FILE__] + mrbs do |t| + file clib => [build.mrbcfile, init] do |t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| @@ -56,11 +161,11 @@ MRuby.each_target do f.puts %Q[] f.puts IO.read(init) mrbc.run f, mrbs, 'mrbtest_irep' - gems.each do |g| + build.gems.each do |g| f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] end f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] - gems.each do |g| + build.gems.each do |g| f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] end f.puts %Q[}] -- cgit v1.2.3 From 133d57cb0d989b956bac899ccc5171351d15fc06 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Sat, 22 Aug 2015 10:21:52 -0400 Subject: Add mruby-test build config and update :test task to use mrbgem binary Removed old mrbgems_test.rake which was merged into mrbgem spec --- Rakefile | 9 +++-- build_config.rb | 10 ++++++ tasks/mrbgems_test.rake | 94 ------------------------------------------------- tasks/mruby_build.rake | 2 +- 4 files changed, 15 insertions(+), 100 deletions(-) delete mode 100644 tasks/mrbgems_test.rake diff --git a/Rakefile b/Rakefile index 89dab05e7..574c1365a 100644 --- a/Rakefile +++ b/Rakefile @@ -26,9 +26,6 @@ load "#{MRUBY_ROOT}/mrblib/mrblib.rake" load "#{MRUBY_ROOT}/tasks/mrbgems.rake" load "#{MRUBY_ROOT}/tasks/libmruby.rake" -load "#{MRUBY_ROOT}/tasks/mrbgems_test.rake" -load "#{MRUBY_ROOT}/test/mrbtest.rake" - load "#{MRUBY_ROOT}/tasks/benchmark.rake" ############################## @@ -117,9 +114,11 @@ task :all => depfiles do end desc "run all mruby tests" -task :test => ["all"] + MRuby.targets.values.map { |t| t.build_mrbtest_lib_only? ? t.libfile("#{t.build_dir}/test/mrbtest") : t.exefile("#{t.build_dir}/test/mrbtest") } do +task :test => ["all"] do MRuby.each_target do - run_test unless build_mrbtest_lib_only? + if gems.find { |v| v.name == 'mruby-test' } + run_test unless build_mrbtest_lib_only? + end end end diff --git a/build_config.rb b/build_config.rb index 3408f19a1..e1178d6b2 100644 --- a/build_config.rb +++ b/build_config.rb @@ -108,6 +108,16 @@ MRuby::Build.new('host-debug') do |conf| # conf.enable_bintest end +MRuby::Build.new('test') do |conf| + toolchain :gcc + + enable_debug + conf.enable_bintest + + conf.gembox 'default' + conf.gem :core => "mruby-test" +end + # Define cross build settings # MRuby::CrossBuild.new('32bit') do |conf| # toolchain :gcc diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake deleted file mode 100644 index 0ee508360..000000000 --- a/tasks/mrbgems_test.rake +++ /dev/null @@ -1,94 +0,0 @@ -MRuby.each_target do - gem_table = gems.generate_gem_table self - - gems.each do |g| - test_rbobj = g.test_rbireps.ext(exts.object) - g.test_objs << test_rbobj - dep_list = gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) - - file test_rbobj => g.test_rbireps - file g.test_rbireps => [g.test_rbfiles].flatten + [File.join(g.dir, 'mrbgem.rake'), g.build.mrbcfile, __FILE__, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t| - FileUtils.mkdir_p File.dirname(t.name) - open(t.name, 'w') do |f| - g.print_gem_test_header(f) - test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| - File.expand_path(g.test_preload, dir) - }.find {|file| File.exist?(file) } - - f.puts %Q[/*] - f.puts %Q[ * This file contains a test code for #{g.name} gem.] - f.puts %Q[ *] - f.puts %Q[ * IMPORTANT:] - f.puts %Q[ * This file was generated!] - f.puts %Q[ * All manual changes will get lost.] - f.puts %Q[ */] - if test_preload.nil? - f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] - else - g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" - end - g.test_rbfiles.flatten.each_with_index do |rbfile, i| - g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" - end - f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty? - dep_list.each do |d| - f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb_state *mrb);] - f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_final(mrb_state *mrb);] - end - f.puts %Q[void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose);] - f.puts %Q[void mrb_t_pass_result(mrb_state *dst, mrb_state *src);] - f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] - unless g.test_rbfiles.empty? - f.puts %Q[ mrb_state *mrb2;] - unless g.test_args.empty? - f.puts %Q[ mrb_value test_args_hash;] - end - f.puts %Q[ int ai;] - g.test_rbfiles.count.times do |i| - f.puts %Q[ ai = mrb_gc_arena_save(mrb);] - f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);] - f.puts %Q[ if (mrb2 == NULL) {] - f.puts %Q[ fprintf(stderr, "Invalid mrb_state, exiting \%s", __FUNCTION__);] - f.puts %Q[ exit(EXIT_FAILURE);] - f.puts %Q[ }] - dep_list.each do |d| - f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);] - f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);] - end - f.puts %Q[ mrb_init_test_driver(mrb2, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));] - if test_preload.nil? - f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] - else - f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] - end - f.puts %Q[ if (mrb2->exc) {] - f.puts %Q[ mrb_print_error(mrb2);] - f.puts %Q[ exit(EXIT_FAILURE);] - f.puts %Q[ }] - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] - - unless g.test_args.empty? - f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ] - g.test_args.each do |arg_name, arg_value| - escaped_arg_name = arg_name.gsub('\\', '\\\\\\\\').gsub('"', '\"') - escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"') - f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ] - end - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "TEST_ARGS"), test_args_hash); ] - end - - f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] if g.custom_test_init? - - f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});] - f.puts %Q[ ] - - f.puts %Q[ mrb_t_pass_result(mrb, mrb2);] - f.puts %Q[ mrb_close(mrb2);] - f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] - end - end - f.puts %Q[}] - end - end - end -end diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 9f8b4eda5..b3a5dcdad 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -249,7 +249,7 @@ EOS def run_test puts ">>> Test #{name} <<<" - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" puts run_bintest if @enable_bintest -- cgit v1.2.3 From 1a45447b8b66159a4a7d0348c4a01a175b3778fd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 27 Aug 2015 17:54:30 +0900 Subject: add String#freeze to the core --- include/mruby/string.h | 11 ++++++++--- src/string.c | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 5228dcbca..c4b31216e 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -59,6 +59,10 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) +#define RSTR_FROZEN_P(s) ((s)->flags & MRB_STR_FROZEN) +#define RSTR_SET_FROZEN_FLAG(s) ((s)->flags |= MRB_STR_FROZEN) +#define RSTR_UNSET_FROZEN_FLAG(s) ((s)->flags &= ~MRB_STR_FROZEN) + #define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s))) #define RSTRING(s) mrb_str_ptr(s) #define RSTRING_PTR(s) RSTR_PTR(RSTRING(s)) @@ -70,9 +74,10 @@ mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_SHARED 1 #define MRB_STR_NOFREE 2 -#define MRB_STR_EMBED 4 -#define MRB_STR_EMBED_LEN_MASK 0xf8 -#define MRB_STR_EMBED_LEN_SHIFT 3 +#define MRB_STR_FROZEN 4 +#define MRB_STR_EMBED 8 +#define MRB_STR_EMBED_LEN_MASK 0x1f0 +#define MRB_STR_EMBED_LEN_SHIFT 4 void mrb_gc_free_str(mrb_state*, struct RString*); MRB_API void mrb_str_modify(mrb_state*, struct RString*); diff --git a/src/string.c b/src/string.c index 45ba38c9d..e5f446bde 100644 --- a/src/string.c +++ b/src/string.c @@ -75,9 +75,18 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_frozen(mrb_state *mrb, struct RString *s) +{ + if (RSTR_FROZEN_P(s)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); + } +} + MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { + check_frozen(mrb, s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -119,6 +128,15 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } +static mrb_value +mrb_str_freeze(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + + RSTR_SET_FROZEN_FLAG(s); + return str; +} + MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -1345,6 +1363,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { long len; + check_frozen(mrb, s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -2514,4 +2533,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); + + mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } -- cgit v1.2.3 From 69e835cd0f1ab24da191e8c09e23288bf64a2fcf Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Thu, 27 Aug 2015 21:44:56 +0900 Subject: Add String#freeze test --- test/t/string.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index ee6fe0848..7326adce9 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -542,3 +542,11 @@ assert('String#each_byte') do assert_equal bytes1, bytes2 end + +assert('String#freeze') do + str = "hello" + str.freeze + + assert_raise(RuntimeError) { str.upcase! } +end + -- cgit v1.2.3 From 0f2b3643ba47a0778eb8571b029e93f16e142b23 Mon Sep 17 00:00:00 2001 From: "Ralph Desir(Mav7)" Date: Sun, 30 Aug 2015 20:20:45 -0400 Subject: Added string markdown. --- doc/api/mruby/string.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/mruby/string.h.md diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From a2f6152be8a2d1775830f32ca955864237fd1081 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Sun, 30 Aug 2015 23:55:55 -0400 Subject: Update string.h.md --- doc/api/mruby/string.h.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md index e69de29bb..b031c564c 100644 --- a/doc/api/mruby/string.h.md +++ b/doc/api/mruby/string.h.md @@ -0,0 +1,10 @@ +### mrb_str_plus +```C + mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); +``` +Adds to strings together. +### mrb_ptr_to_str +```C + mrb_value mrb_ptr_to_str(mrb_state *, void*); +``` +Converts pointer into a Ruby string. -- cgit v1.2.3 From 00dd2dfa3939d15e437d1779a7de23b1018a7cd7 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 31 Aug 2015 14:11:17 -0400 Subject: Update string.h.md --- doc/api/mruby/string.h.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md index b031c564c..e2a10c2cf 100644 --- a/doc/api/mruby/string.h.md +++ b/doc/api/mruby/string.h.md @@ -8,3 +8,8 @@ Adds to strings together. mrb_value mrb_ptr_to_str(mrb_state *, void*); ``` Converts pointer into a Ruby string. +### mrb_obj_as_string +```C + mrb_obj_as_string(mrb_state *mrb, mrb_value obj); +``` +Returns an object as a Ruby string. -- cgit v1.2.3 From b432f12fddafb6ad4ac987361bf07560efbc8fad Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Mon, 31 Aug 2015 18:54:42 -0400 Subject: run bintests within subfolders of bintest/ --- test/bintest.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bintest.rb b/test/bintest.rb index 0ff3341a0..49990abb9 100644 --- a/test/bintest.rb +++ b/test/bintest.rb @@ -2,7 +2,7 @@ $:.unshift File.dirname(File.dirname(File.expand_path(__FILE__))) require 'test/assert.rb' ARGV.each do |gem| - Dir["#{gem}/bintest/*.rb"].each do |file| + Dir["#{gem}/bintest/**/*.rb"].each do |file| load file end end -- cgit v1.2.3 From d78d0017342ef42cc0d5db517446c805e23ae344 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Mon, 31 Aug 2015 23:16:45 -0400 Subject: Update string.h.md --- doc/api/mruby/string.h.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md index e2a10c2cf..428a3ca40 100644 --- a/doc/api/mruby/string.h.md +++ b/doc/api/mruby/string.h.md @@ -10,6 +10,36 @@ Adds to strings together. Converts pointer into a Ruby string. ### mrb_obj_as_string ```C - mrb_obj_as_string(mrb_state *mrb, mrb_value obj); + mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); ``` Returns an object as a Ruby string. +### mrb_str_resize +```C + mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len); +``` +Resizes the string's length. +### mrb_str_substr +```C + mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); +``` +Returns a sub string. +### mrb_string_type +```C + mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); +``` +Returns a Ruby string type. +### mrb_str_new_cstr +```C + const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); +``` +Returns a Ruby string as a C string. +### mrb_str_dup +```C + mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); +``` +Duplicates a string object. +### mrb_str_intern +```C + mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); +``` +Returns a symbol from a passed in string. -- cgit v1.2.3 From a2385c05f5f07b30c039a46b497ae22bc0c5e212 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Mon, 31 Aug 2015 20:36:33 +0900 Subject: Refactor version.h macros --- include/mruby/version.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/mruby/version.h b/include/mruby/version.h index ea044d6da..b3e4df029 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -7,25 +7,27 @@ #ifndef MRUBY_VERSION_H #define MRUBY_VERSION_H +#define MRB_STRINGIZE0(expr) #expr +#define MRB_STRINGIZE(expr) MRB_STRINGIZE0(expr) + #define MRUBY_RUBY_VERSION "1.9" #define MRUBY_RUBY_ENGINE "mruby" -#define MRUBY_VERSION "1.1.0" #define MRUBY_RELEASE_MAJOR 1 #define MRUBY_RELEASE_MINOR 1 #define MRUBY_RELEASE_TEENY 1 -#define MRUBY_RELEASE_NO 10101 -#define MRUBY_RELEASE_DATE "2014-11-19" + +#define MRUBY_VERSION MRB_STRINGIZE(MRUBY_RELEASE_MAJOR)"."MRB_STRINGIZE(MRUBY_RELEASE_MINOR)"."MRB_STRINGIZE(MRUBY_RELEASE_TEENY) +#define MRUBY_RELEASE_NO (MRUBY_RELEASE_MAJOR * 100 * 100 + MRUBY_RELEASE_MINOR * 100 + MRUBY_RELEASE_TEENY) #define MRUBY_RELEASE_YEAR 2014 #define MRUBY_RELEASE_MONTH 11 #define MRUBY_RELEASE_DAY 19 +#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR)"-"MRB_STRINGIZE(MRUBY_RELEASE_MONTH)"-"MRB_STRINGIZE(MRUBY_RELEASE_DAY) #define MRUBY_BIRTH_YEAR 2010 #define MRUBY_AUTHOR "mruby developers" -#define MRB_STRINGIZE0(expr) #expr -#define MRB_STRINGIZE(expr) MRB_STRINGIZE0(expr) #define MRUBY_DESCRIPTION \ "mruby " MRUBY_VERSION \ -- cgit v1.2.3 From e9b4cb11cf7b6b8b45e5a0a03e6eda3f12a93407 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Mon, 31 Aug 2015 20:32:30 +0900 Subject: Add a global const variable MRUBY_RELEASE_NO --- src/version.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/version.c b/src/version.c index 7aac44d62..fc3b2fc7a 100644 --- a/src/version.c +++ b/src/version.c @@ -7,6 +7,7 @@ mrb_init_version(mrb_state* mrb) mrb_define_global_const(mrb, "RUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_RUBY_VERSION)); mrb_define_global_const(mrb, "RUBY_ENGINE", mrb_str_new_lit(mrb, MRUBY_RUBY_ENGINE)); mrb_define_global_const(mrb, "MRUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_VERSION)); + mrb_define_global_const(mrb, "MRUBY_RELEASE_NO", mrb_fixnum_value(MRUBY_RELEASE_NO)); mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE)); mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION)); mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT)); -- cgit v1.2.3 From 8ad8c547dda2850e67113f6d5a8c4b4d186fe27f Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Tue, 1 Sep 2015 13:50:27 -0400 Subject: Update string.h.md --- doc/api/mruby/string.h.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md index 428a3ca40..1268792e0 100644 --- a/doc/api/mruby/string.h.md +++ b/doc/api/mruby/string.h.md @@ -1,3 +1,7 @@ +## Macros +### mrb_str_ptr(s) +Returns a pointer from a Ruby string. +## Functions ### mrb_str_plus ```C mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); @@ -43,3 +47,45 @@ Duplicates a string object. mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); ``` Returns a symbol from a passed in string. +### mrb_str_to_str +```C + mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); +``` +Returns a converted string type. +### mrb_str_equal +```C + mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); +``` +Returns true if the strings match and false if the strings don't match. +### mrb_str_cat +```C + mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); +``` +Returns a concated string comprised of a Ruby string and a C string. +### mrb_str_cat_cstr +```C + mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2); +``` +Returns a concated string comprised of a Ruby string and a C string(A shorter alternative to mrb_str_cat). +### mrb_str_append +```C + mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); +``` +Adds str2 to the end of str1. +### mrb_str_cmp +```C + int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); +``` +Returns 0 if both Ruby strings are equal. +Returns a value < 0 if Ruby str1 is less than Ruby str2. +Returns a value > 0 if Ruby str2 is greater than Ruby str1. +### mrb_str_to_cstr +```C + char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str); +``` +Returns a C string from a Ruby string. +### mrb_str_inspect +```C + mrb_str_inspect(mrb_state *mrb, mrb_value str); +``` +Returns a printable version of str, surrounded by quote marks, with special characters escaped. -- cgit v1.2.3 From 80598f40bf23d310530427808885826e4436330d Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Tue, 1 Sep 2015 20:54:27 -0400 Subject: mruby-test should be opt-in --- mrbgems/full-core.gembox | 2 +- travis_config.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mrbgems/full-core.gembox b/mrbgems/full-core.gembox index d1ff5f414..9a5b7081b 100644 --- a/mrbgems/full-core.gembox +++ b/mrbgems/full-core.gembox @@ -4,6 +4,6 @@ MRuby::GemBox.new do |conf| Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x| g = File.basename File.dirname x - conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger)$/ + conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger|test)$/ end end diff --git a/travis_config.rb b/travis_config.rb index 2b4059cf1..458473f96 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -38,3 +38,13 @@ MRuby::Build.new('cxx_abi') do |conf| build_mrbc_exec end + +MRuby::Build.new('test') do |conf| + toolchain :gcc + + enable_debug + conf.enable_bintest + + conf.gembox 'full-core' + conf.gem :core => "mruby-test" +end -- cgit v1.2.3 From 5ed13da7d6056c76a5f8063a2b9b2cd57ac323bf Mon Sep 17 00:00:00 2001 From: jbreeden Date: Tue, 1 Sep 2015 18:09:32 -0700 Subject: C++ 11 requires a space between literal and identifiers --- include/mruby/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby/version.h b/include/mruby/version.h index b3e4df029..c2a9b6306 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -17,12 +17,12 @@ #define MRUBY_RELEASE_MINOR 1 #define MRUBY_RELEASE_TEENY 1 -#define MRUBY_VERSION MRB_STRINGIZE(MRUBY_RELEASE_MAJOR)"."MRB_STRINGIZE(MRUBY_RELEASE_MINOR)"."MRB_STRINGIZE(MRUBY_RELEASE_TEENY) +#define MRUBY_VERSION MRB_STRINGIZE(MRUBY_RELEASE_MAJOR) "." MRB_STRINGIZE(MRUBY_RELEASE_MINOR) "." MRB_STRINGIZE(MRUBY_RELEASE_TEENY) #define MRUBY_RELEASE_NO (MRUBY_RELEASE_MAJOR * 100 * 100 + MRUBY_RELEASE_MINOR * 100 + MRUBY_RELEASE_TEENY) #define MRUBY_RELEASE_YEAR 2014 #define MRUBY_RELEASE_MONTH 11 #define MRUBY_RELEASE_DAY 19 -#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR)"-"MRB_STRINGIZE(MRUBY_RELEASE_MONTH)"-"MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR) "-" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) "-" MRB_STRINGIZE(MRUBY_RELEASE_DAY) #define MRUBY_BIRTH_YEAR 2010 -- cgit v1.2.3 From c0ff5b475f6338e51f964a17697dee6d851d57a9 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Tue, 1 Sep 2015 23:43:36 -0400 Subject: Typo in mruby-bin-debugger/mrbgem.rake --- mrbgems/mruby-bin-debugger/mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-bin-debugger/mrbgem.rake b/mrbgems/mruby-bin-debugger/mrbgem.rake index b9d664779..764f431af 100755 --- a/mrbgems/mruby-bin-debugger/mrbgem.rake +++ b/mrbgems/mruby-bin-debugger/mrbgem.rake @@ -1,7 +1,7 @@ MRuby::Gem::Specification.new('mruby-bin-debugger') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'mruby debuggeer command' + spec.summary = 'mruby debugger command' spec.add_dependency('mruby-eval', :core => 'mruby-eval') -- cgit v1.2.3 From 14f0e4a4e4657fe0dc6512cf735c9c75201bd406 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 2 Sep 2015 15:09:50 +0900 Subject: update string.h.md; ref #2931 --- doc/api/mruby/string.h.md | 2 +- src/string.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md index 1268792e0..7bf94df5b 100644 --- a/doc/api/mruby/string.h.md +++ b/doc/api/mruby/string.h.md @@ -69,7 +69,7 @@ Returns a concated string comprised of a Ruby string and a C string. Returns a concated string comprised of a Ruby string and a C string(A shorter alternative to mrb_str_cat). ### mrb_str_append ```C - mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); + mrb_value mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2); ``` Adds str2 to the end of str1. ### mrb_str_cmp diff --git a/src/string.c b/src/string.c index e5f446bde..73ef341bb 100644 --- a/src/string.c +++ b/src/string.c @@ -2385,10 +2385,10 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) } MRB_API mrb_value -mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2) +mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { str2 = mrb_str_to_str(mrb, str2); - return mrb_str_cat_str(mrb, str, str2); + return mrb_str_cat_str(mrb, str1, str2); } #define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ -- cgit v1.2.3 From 6ddd79fd0ebfd88a9b36be08d509e665a9322567 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 2 Sep 2015 21:46:51 +0900 Subject: ensure must not be called before rescue; fix #2933 --- src/vm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vm.c b/src/vm.c index 00636a870..8419931d0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1486,9 +1486,6 @@ RETRY_TRY_BLOCK: if (ci->ridx == 0) goto L_STOP; goto L_RESCUE; } - while (eidx > ci[-1].eidx) { - ecall(mrb, --eidx); - } while (ci[0].ridx == ci[-1].ridx) { cipop(mrb); ci = mrb->c->ci; -- cgit v1.2.3 From 74696ffd9625e4dca43aa010d71020f10030de24 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 2 Sep 2015 22:29:01 +0900 Subject: Float << and >> should be more compatible to Fixnum --- mrblib/numeric.rb | 26 ++++++++++++++++++++++---- test/t/float.rb | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 206185e78..6e4c5027f 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -165,12 +165,30 @@ class Float # floats should be compatible to integers. def >> other n = self.to_i - other.to_i.times { n /= 2 } - n + other = other.to_i + if other < 0 + n << -other + else + other.times { n /= 2 } + if n.abs < 1 + if n >= 0 + 0 + else + -1 + end + else + n.to_i + end + end end def << other n = self.to_i - other.to_i.times { n *= 2 } - n.to_i + other = other.to_i + if other < 0 + n >> -other + else + other.times { n *= 2 } + n + end end end diff --git a/test/t/float.rb b/test/t/float.rb index d45709173..0aab0b1f2 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -178,3 +178,25 @@ assert('Float#nan?') do assert_false (1.0/0.0).nan? assert_false (-1.0/0.0).nan? end + +assert('Float#<<') do + # Left Shift by one + assert_equal 46, 23.0 << 1 + + # Left Shift by a negative is Right Shift + assert_equal 23, 46.0 << -1 +end + +assert('Float#>>') do + # Right Shift by one + assert_equal 23, 46.0 >> 1 + + # Right Shift by a negative is Left Shift + assert_equal 46, 23.0 >> -1 + + # Don't raise on large Right Shift + assert_equal 0, 23.0 >> 128 + + # Don't raise on large Right Shift + assert_equal -1, -23.0 >> 128 +end -- cgit v1.2.3 From 87564dc98f22a7710f9e6565f6750bfaa220f965 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Wed, 2 Sep 2015 09:52:37 -0400 Subject: Make travis happy We have do this because mruby's test files are found using MRUBY_ROOT, like this: mrbs = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb") --- test/t/syntax.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index dc1a4a3b9..fb6ffe408 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -1,6 +1,6 @@ assert('__FILE__') do - file = __FILE__ - assert_true 'test/t/syntax.rb' == file || 'test\t\syntax.rb' == file + file = __FILE__.split('test/')[1] + assert_true 't/syntax.rb' == file || 't\syntax.rb' == file end assert('__LINE__') do -- cgit v1.2.3 From 3a462fe4687fa2a52d2c9c20d10ae46901292b99 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 2 Sep 2015 23:41:51 +0900 Subject: Integer << and >> to use Float instead of raising RangeError --- src/numeric.c | 12 +++++++----- test/t/integer.rb | 10 ---------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 14c0b76a6..1a3c903f0 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -820,11 +820,13 @@ fix_xor(mrb_state *mrb, mrb_value x) static mrb_value lshift(mrb_state *mrb, mrb_int val, mrb_int width) { - mrb_assert(width >= 0); + mrb_assert(width > 0); if (width > NUMERIC_SHIFT_WIDTH_MAX) { - mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)", - mrb_fixnum_value(width), - mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX)); + mrb_float f = (mrb_float)val; + while (width--) { + f *= 2; + } + return mrb_float_value(mrb, f); } return mrb_fixnum_value(val << width); } @@ -832,7 +834,7 @@ lshift(mrb_state *mrb, mrb_int val, mrb_int width) static mrb_value rshift(mrb_int val, mrb_int width) { - mrb_assert(width >= 0); + mrb_assert(width > 0); if (width >= NUMERIC_SHIFT_WIDTH_MAX) { if (val < 0) { return mrb_fixnum_value(-1); diff --git a/test/t/integer.rb b/test/t/integer.rb index 6b8cc308d..be3c13db2 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -147,11 +147,6 @@ assert('Integer#<<', '15.2.8.3.12') do # Left Shift by a negative is Right Shift assert_equal 23, 46 << -1 - - # Raise when shift is too large - assert_raise(RangeError) do - 2 << 128 - end end assert('Integer#>>', '15.2.8.3.13') do @@ -165,11 +160,6 @@ assert('Integer#>>', '15.2.8.3.13') do # Don't raise on large Right Shift assert_equal 0, 23 >> 128 - - # Raise when shift is too large - assert_raise(RangeError) do - 2 >> -128 - end end assert('Integer#ceil', '15.2.8.3.14') do -- cgit v1.2.3 From e35c3aff83d400dfe27fe105b7e282ac81b1197a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Sep 2015 00:14:37 +0900 Subject: unsigned long may be smaller than mrb_int; use uint64_t instead; fix #2935 --- mrbgems/mruby-sprintf/src/sprintf.c | 2 +- src/string.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index de216f69f..81b48b10d 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -73,7 +73,7 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) { char buf[64], *b = buf + sizeof buf; mrb_int num = mrb_fixnum(x); - unsigned long val = (unsigned long)num; + uint64_t val = (uint64_t)num; char d; if (base != 2) { diff --git a/src/string.c b/src/string.c index 73ef341bb..08caf3bae 100644 --- a/src/string.c +++ b/src/string.c @@ -1863,7 +1863,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) const char *p; char sign = 1; int c, uscore; - unsigned long n = 0; + uint64_t n = 0; mrb_int val; #define conv_digit(c) \ @@ -1983,9 +1983,9 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) } n *= base; n += c; - } - if (n > MRB_INT_MAX) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str)); + if (n > MRB_INT_MAX) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str)); + } } val = n; if (badcheck) { -- cgit v1.2.3 From 7b5f8b07285eeb9900ef1a85cb2c764fbbd34461 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Sep 2015 01:39:17 +0900 Subject: remove trailing spaces from bc9c47d5 --- build_config.rb | 3 ++- include/mruby/dump.h | 4 ++-- src/load.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build_config.rb b/build_config.rb index e1178d6b2..34b92637c 100644 --- a/build_config.rb +++ b/build_config.rb @@ -21,6 +21,7 @@ MRuby::Build.new do |conf| # include the default GEMs conf.gembox 'default' + conf.gem :core => 'mruby-eval' # C compiler settings # conf.cc do |cc| @@ -105,7 +106,7 @@ MRuby::Build.new('host-debug') do |conf| conf.gem :core => "mruby-bin-debugger" # bintest - # conf.enable_bintest + conf.enable_bintest end MRuby::Build.new('test') do |conf| diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 45774d872..4cee3c0ac 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -17,8 +17,8 @@ extern "C" { #define DUMP_DEBUG_INFO 1 #define DUMP_ENDIAN_BIG 2 #define DUMP_ENDIAN_LIL 4 -#define DUMP_ENDIAN_NAT 6 -#define DUMP_ENDIAN_MASK 6 +#define DUMP_ENDIAN_NAT 6 +#define DUMP_ENDIAN_MASK 6 int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size); #ifdef ENABLE_STDIO diff --git a/src/load.c b/src/load.c index a9f1641bf..36fae9aee 100644 --- a/src/load.c +++ b/src/load.c @@ -529,7 +529,7 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_LIL; - else + else *flags |= FLAG_BYTEORDER_NATIVE; } else { -- cgit v1.2.3 From cc0b28373a304541308b6386f4be15aedf30ce43 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Sep 2015 01:46:35 +0900 Subject: clear DUMP_ENDIAN flags before setting --- mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index 301dde1c6..2f507904a 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -119,10 +119,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) args->flags |= DUMP_DEBUG_INFO; break; case 'E': - args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); + args->flags = DUMP_ENDIAN_BIG | (args->flags & ~DUMP_ENDIAN_MASK); break; case 'e': - args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); + args->flags = DUMP_ENDIAN_LIL | (args->flags & ~DUMP_ENDIAN_MASK); break; case 'h': return -1; -- cgit v1.2.3 From da0dc6937da11dec6c47f93f24bfac3ca02d1464 Mon Sep 17 00:00:00 2001 From: "Ralph Desir(Mav7)" Date: Wed, 2 Sep 2015 18:19:53 -0400 Subject: doc/api/mruby/version.h.md --- doc/api/mruby/version.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/mruby/version.h.md diff --git a/doc/api/mruby/version.h.md b/doc/api/mruby/version.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 6beae5ec71718f36efbb60037f929f1b5e279208 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Wed, 2 Sep 2015 18:45:03 -0400 Subject: Created version.h markdown. --- doc/api/mruby/version.h.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/api/mruby/version.h.md b/doc/api/mruby/version.h.md index e69de29bb..daf87077d 100644 --- a/doc/api/mruby/version.h.md +++ b/doc/api/mruby/version.h.md @@ -0,0 +1,33 @@ +#### Macros +### MRUBY_RUBY_VERSION +The version of Ruby used by mruby. +### MRUBY_RUBY_ENGINE +Ruby engine. +### MRUBY_VERSION +The mruby version. +### MRUBY_RELEASE_MAJOR +Major release version. +### MRUBY_RELEASE_MINOR +Minor release version. +### MRUBY_RELEASE_NO +Release number. +### MRUBY_RELEASE_DATE +Release date as a string. +### MRUBY_RELEASE_YEAR +Release year. +### MRUBY_RELEASE_MONTH +Release month. +### MRUBY_RELEASE_DAY +Release day. +### MRUBY_BIRTH_YEAR +The year mruby was first created. +### MRUBY_AUTHOR +Mruby's authors. +### MRB_STRINGIZE0(expr) +A passed in expression. +### MRB_STRINGIZE(expr) +Passes in an expression to MRB_STRINGIZE0. +### MRUBY_DESCRIPTION +mruby's version, and release date. +### MRUBY_COPYRIGHT +mruby's copyright information. -- cgit v1.2.3 From 1bd5c4859615f3b6012093ace07b032c86336c69 Mon Sep 17 00:00:00 2001 From: "Ralph Desir(Mav7)" Date: Wed, 2 Sep 2015 18:52:16 -0400 Subject: Added regular expression header markdown. --- doc/api/mruby/re.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/mruby/re.h.md diff --git a/doc/api/mruby/re.h.md b/doc/api/mruby/re.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 79aa0866cea908d9ce03da4a3828816e1abed7cb Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Wed, 2 Sep 2015 18:57:00 -0400 Subject: Added reg.h markdown. --- doc/api/mruby/re.h.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/api/mruby/re.h.md b/doc/api/mruby/re.h.md index e69de29bb..01e18c6a5 100644 --- a/doc/api/mruby/re.h.md +++ b/doc/api/mruby/re.h.md @@ -0,0 +1,3 @@ +#### Macros +### REGEXP_CLASS +A string with the name of the REGEXP class. -- cgit v1.2.3 From bacb8268682e8d931a00e7894ed7904bc789d8c4 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Wed, 2 Sep 2015 23:11:18 -0400 Subject: Add build_mrbtest after config block is evaluated This allows us to add `enable_test` anywhere in a build target, without having to worry about the order in which they are included. Previously, there was a bug that occured when adding 'mruby-test' gem to dependencies before additional gems. Instead of adding the 'mruby-test' gem dependency manually to a test build, we now only need to call `enable_test` in the target. This also allows us to call `test_enabled?` downstream when running mruby tests ourselves. /cc #2924 --- Rakefile | 4 +--- build_config.rb | 2 +- mrbgems/mruby-test/mrbgem.rake | 2 +- tasks/mruby_build.rake | 21 ++++++++++++++++++--- travis_config.rb | 12 ++---------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Rakefile b/Rakefile index 574c1365a..8a8912af5 100644 --- a/Rakefile +++ b/Rakefile @@ -116,9 +116,7 @@ end desc "run all mruby tests" task :test => ["all"] do MRuby.each_target do - if gems.find { |v| v.name == 'mruby-test' } - run_test unless build_mrbtest_lib_only? - end + run_test if test_enabled? end end diff --git a/build_config.rb b/build_config.rb index 34b92637c..d3c1ebc1f 100644 --- a/build_config.rb +++ b/build_config.rb @@ -114,9 +114,9 @@ MRuby::Build.new('test') do |conf| enable_debug conf.enable_bintest + conf.enable_test conf.gembox 'default' - conf.gem :core => "mruby-test" end # Define cross build settings diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 8370f4713..b6b247ff6 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -32,7 +32,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end end - gem_table = build.gems.generate_gem_table self + gem_table = build.gems.generate_gem_table build build.gems.each do |g| test_rbobj = g.test_rbireps.ext(exts.object) diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index b3a5dcdad..6863b635a 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -46,7 +46,7 @@ module MRuby include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir attr_reader :libmruby, :gems, :toolchains - attr_writer :enable_bintest + attr_writer :enable_bintest, :enable_test COMPILERS = %w(cc cxx objc asm) COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) @@ -85,6 +85,8 @@ module MRuby @build_mrbtest_lib_only = false @cxx_abi_enabled = false @cxx_exception_disabled = false + @enable_bintest = false + @enable_test = false @toolchains = [] MRuby.targets[@name] = self @@ -94,6 +96,7 @@ module MRuby MRuby.targets[@name].instance_eval(&block) build_mrbc_exec if name == 'host' + build_mrbtest if test_enabled? end def enable_debug @@ -170,6 +173,18 @@ EOS MRUBY_ROOT end + def enable_test + @enable_test = true + end + + def test_enabled? + @enable_test + end + + def build_mrbtest + gem :core => 'mruby-test' + end + def build_mrbc_exec gem :core => 'mruby-bin-mrbc' end @@ -252,7 +267,7 @@ EOS mrbtest = exefile("#{build_dir}/bin/mrbtest") sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" puts - run_bintest if @enable_bintest + run_bintest if bintest_enabled? end def run_bintest @@ -297,7 +312,7 @@ EOS end def run_test - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") if (@test_runner.command == nil) puts "You should run #{mrbtest} on target device." puts diff --git a/travis_config.rb b/travis_config.rb index 458473f96..4ee6d752b 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -22,6 +22,7 @@ MRuby::Build.new do |conf| c.defines += %w(MRB_GC_FIXED_ARENA) end conf.enable_bintest + conf.enable_test end MRuby::Build.new('cxx_abi') do |conf| @@ -33,18 +34,9 @@ MRuby::Build.new('cxx_abi') do |conf| c.defines += %w(MRB_GC_FIXED_ARENA) end conf.enable_bintest + conf.enable_test enable_cxx_abi build_mrbc_exec end - -MRuby::Build.new('test') do |conf| - toolchain :gcc - - enable_debug - conf.enable_bintest - - conf.gembox 'full-core' - conf.gem :core => "mruby-test" -end -- cgit v1.2.3 From 93aaa0673678ec53cf977ac908e962225db962cf Mon Sep 17 00:00:00 2001 From: "Ralph Desir(Mav7)" Date: Thu, 3 Sep 2015 14:16:57 -0400 Subject: Added range markdown. --- doc/api/mruby/range.h.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/api/mruby/range.h.md diff --git a/doc/api/mruby/range.h.md b/doc/api/mruby/range.h.md new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From e1beb502ab133d4bfae5fa3df856aa2b851e2655 Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 3 Sep 2015 14:19:02 -0400 Subject: Cleaned up the re.h markdown. --- doc/api/mruby/re.h.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/mruby/re.h.md b/doc/api/mruby/re.h.md index 01e18c6a5..f5cd2a71e 100644 --- a/doc/api/mruby/re.h.md +++ b/doc/api/mruby/re.h.md @@ -1,3 +1,3 @@ -#### Macros -### REGEXP_CLASS +### Macros +#### REGEXP_CLASS A string with the name of the REGEXP class. -- cgit v1.2.3 From 8a09515c6c7b1e8315c6b1accb92cb93d8e8138c Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 3 Sep 2015 14:20:16 -0400 Subject: Cleaned up the version.h markdown. --- doc/api/mruby/version.h.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/api/mruby/version.h.md b/doc/api/mruby/version.h.md index daf87077d..f627b1da1 100644 --- a/doc/api/mruby/version.h.md +++ b/doc/api/mruby/version.h.md @@ -1,33 +1,33 @@ -#### Macros -### MRUBY_RUBY_VERSION +### Macros +#### MRUBY_RUBY_VERSION The version of Ruby used by mruby. -### MRUBY_RUBY_ENGINE +#### MRUBY_RUBY_ENGINE Ruby engine. -### MRUBY_VERSION +#### MRUBY_VERSION The mruby version. -### MRUBY_RELEASE_MAJOR +#### MRUBY_RELEASE_MAJOR Major release version. -### MRUBY_RELEASE_MINOR +#### MRUBY_RELEASE_MINOR Minor release version. -### MRUBY_RELEASE_NO +#### MRUBY_RELEASE_NO Release number. -### MRUBY_RELEASE_DATE +#### MRUBY_RELEASE_DATE Release date as a string. -### MRUBY_RELEASE_YEAR +#### MRUBY_RELEASE_YEAR Release year. -### MRUBY_RELEASE_MONTH +#### MRUBY_RELEASE_MONTH Release month. -### MRUBY_RELEASE_DAY +#### MRUBY_RELEASE_DAY Release day. -### MRUBY_BIRTH_YEAR +#### MRUBY_BIRTH_YEAR The year mruby was first created. -### MRUBY_AUTHOR +#### MRUBY_AUTHOR Mruby's authors. -### MRB_STRINGIZE0(expr) +#### MRB_STRINGIZE0(expr) A passed in expression. -### MRB_STRINGIZE(expr) +#### MRB_STRINGIZE(expr) Passes in an expression to MRB_STRINGIZE0. -### MRUBY_DESCRIPTION +#### MRUBY_DESCRIPTION mruby's version, and release date. -### MRUBY_COPYRIGHT +#### MRUBY_COPYRIGHT mruby's copyright information. -- cgit v1.2.3 From 743432d4ecc2052f6808d1e1012eb356e85ccb1e Mon Sep 17 00:00:00 2001 From: Ralph Desir Date: Thu, 3 Sep 2015 14:52:21 -0400 Subject: Update range.h.md --- doc/api/mruby/range.h.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/doc/api/mruby/range.h.md b/doc/api/mruby/range.h.md index e69de29bb..188e6ede6 100644 --- a/doc/api/mruby/range.h.md +++ b/doc/api/mruby/range.h.md @@ -0,0 +1,47 @@ +#### mrb_range_new +```C + mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool); +``` +Initializes a Range. The first mrb_value being the beginning value and second being the ending value. +The third parameter is an mrb_bool value that represents the inclusion or exclusion of the last value. +If the third parameter is 0 then it includes the last value in the range. If the third parameter is 1 +then it excludes the last value in the range. +C code +```C + #include + #include + #include "mruby/range.h" // Needs the range header. + #include "mruby/compile.h" + + int main(int argc, char *argv[]) + { + mrb_int beg = 0; + mrb_int end = 2; + mrb_bool exclude = 1; + mrb_value range_obj; + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + FILE *fp = fopen("test.rb","r"); + range_obj = mrb_range_new(mrb, mrb_fixnum_value(beg), mrb_fixnum_value(end), exclude); + mrb_value obj = mrb_load_file(mrb,fp); + mrb_funcall(mrb, obj, "method_name", 1, range_obj); + fclose(fp); + mrb_close(mrb); + return 0; + } +``` +Ruby code +```Ruby + class Example_Class + def method_name(a) + puts a + puts a.class + end + end + Example_Class.new +``` +This returns the following: +```Ruby + 0...2 + Range +``` -- cgit v1.2.3 From c6860bc0c4978d3158a96b32d4fe9965c03424dd Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Fri, 4 Sep 2015 10:50:58 -0400 Subject: Allow rbfiles in mrblib and test to have subdirs --- tasks/mrbgem_spec.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index d13e7733f..74aa5b817 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -54,7 +54,7 @@ module MRuby end @linker = LinkerConfig.new([], [], [], []) - @rbfiles = Dir.glob("#{dir}/mrblib/*.rb").sort + @rbfiles = Dir.glob("#{dir}/mrblib/**/*.rb").sort @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) end @@ -62,7 +62,7 @@ module MRuby @generate_functions = !(@rbfiles.empty? && @objs.empty?) @objs << objfile("#{build_dir}/gem_init") if @generate_functions - @test_rbfiles = Dir.glob("#{dir}/test/*.rb") + @test_rbfiles = Dir.glob("#{dir}/test/**/*.rb") @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) end -- cgit v1.2.3 From 6ced9c3752eefbb1b2a9ad971953f82f530c1a04 Mon Sep 17 00:00:00 2001 From: Jun Hiroe Date: Sat, 5 Sep 2015 00:04:43 +0900 Subject: Revert 7b5f8b0 except removing trailing spaces --- build_config.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build_config.rb b/build_config.rb index d3c1ebc1f..96b1d4684 100644 --- a/build_config.rb +++ b/build_config.rb @@ -21,7 +21,6 @@ MRuby::Build.new do |conf| # include the default GEMs conf.gembox 'default' - conf.gem :core => 'mruby-eval' # C compiler settings # conf.cc do |cc| @@ -106,7 +105,7 @@ MRuby::Build.new('host-debug') do |conf| conf.gem :core => "mruby-bin-debugger" # bintest - conf.enable_bintest + # conf.enable_bintest end MRuby::Build.new('test') do |conf| -- cgit v1.2.3 From 2550edd570f1d7485e862ce11ceb50ea59dee3c5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 5 Sep 2015 02:01:02 +0900 Subject: remove `origin` member to implement prepend from struct RClass; ref #2885 instead origin is saved in ICLASS with MRB_FLAG_IS_ORIGIN set. --- include/mruby/class.h | 10 +++++++++- src/class.c | 44 ++++++++++++++++++++++++-------------------- src/kernel.c | 29 +++++++++++++++-------------- src/object.c | 2 +- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 80a0cbe35..85f3e12c6 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -16,7 +16,6 @@ struct RClass { struct iv_tbl *iv; struct kh_mt *mt; struct RClass *super; - struct RClass *origin; }; #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) @@ -50,7 +49,16 @@ mrb_class(mrb_state *mrb, mrb_value v) } // TODO: figure out where to put user flags +#define MRB_FLAG_IS_PREPENDED (1 << 19) #define MRB_FLAG_IS_ORIGIN (1 << 20) +#define MRB_CLASS_ORIGIN(c) do {\ + if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + c = c->super;\ + while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + c = c->super;\ + }\ + }\ +} while (0) #define MRB_INSTANCE_TT_MASK (0xFF) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) diff --git a/src/class.c b/src/class.c index 462ab40b5..c3c3e0b8f 100644 --- a/src/class.c +++ b/src/class.c @@ -76,7 +76,6 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->origin = sc; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -188,6 +187,13 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) return c; } +static struct RClass* +find_origin(struct RClass *c) +{ + MRB_CLASS_ORIGIN(c); + return c; +} + static struct RClass* define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer) { @@ -195,7 +201,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); - c = c->origin; + MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", mrb_sym2str(mrb, name), @@ -327,7 +333,8 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro { khash_t(mt) *h; khiter_t k; - h = c->origin->mt; + MRB_CLASS_ORIGIN(c); + h = c->mt; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); @@ -809,7 +816,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); - c->origin = c; if (super) { c->super = super; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); @@ -824,7 +830,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) static void boot_initmod(mrb_state *mrb, struct RClass *mod) { - mod->origin = mod; mod->mt = kh_init(mt, mrb); } @@ -835,9 +840,9 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) if (m->tt == MRB_TT_ICLASS) { m = m->c; } - ic->origin = ic; + MRB_CLASS_ORIGIN(m); ic->iv = m->iv; - ic->mt = m->origin->mt; + ic->mt = m->mt; ic->super = super; if (m->tt == MRB_TT_ICLASS) { ic->c = m->c; @@ -851,12 +856,12 @@ static int include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) { struct RClass *p, *ic; - void *klass_mt = c->origin->mt; + void *klass_mt = find_origin(c)->mt; while (m) { int superclass_seen = 0; - if (m->origin != m) + if (m->flags & MRB_FLAG_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -891,7 +896,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, c->origin, m, 1); + int changed = include_module_at(mrb, c, find_origin(c), m, 1); if (changed < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } @@ -903,17 +908,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - origin = c->origin; - if (origin == c) { + if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FLAG_IS_ORIGIN; - origin->origin = origin; origin->super = c->super; c->super = origin; - c->origin = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); - mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->origin); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); + c->flags |= MRB_FLAG_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1026,7 +1029,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (c->origin == c) { + else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1051,8 +1054,9 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); - struct RClass *origin = c->origin; + struct RClass *origin = c; + MRB_CLASS_ORIGIN(origin); result = mrb_ary_new(mrb); while (c) { if (c != origin && c->tt == MRB_TT_ICLASS) { @@ -1391,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->origin->super; + c = find_origin(c)->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->origin->super; + c = find_origin(c)->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1990,7 +1994,7 @@ static void remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) { struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = c->origin->mt; + khash_t(mt) *h = find_origin(c)->mt; khiter_t k; if (h) { diff --git a/src/kernel.c b/src/kernel.c index 36ad683ee..225f7fa54 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -240,19 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) /* copy singleton(unnamed) class */ struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class); - if ((mrb_type(obj) == MRB_TT_CLASS) || - (mrb_type(obj) == MRB_TT_SCLASS)) { /* BUILTIN_TYPE(obj) == T_CLASS */ + if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) { clone->c = clone; } else { clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); } - - if (klass->origin != klass) - clone->origin = klass->origin; - else - clone->origin = clone; - clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -276,10 +269,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->origin != sc) { - dc->origin = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(sc->origin))); - } else { - dc->origin = dc; + if (sc->flags & MRB_FLAG_IS_PREPENDED) { + struct RClass *c0 = sc->super; + struct RClass *c1 = dc; + + /* copy prepended iclasses */ + while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1 = c1->super; + c0 = c0->super; + } + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1->super->flags |= MRB_FLAG_IS_ORIGIN; } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; @@ -657,8 +658,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); - if (!recur && klass->origin != klass) { - klass = klass->origin; + if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); prepended = 1; } diff --git a/src/object.c b/src/object.c index c834ee04f..2e0bd245f 100644 --- a/src/object.c +++ b/src/object.c @@ -487,7 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); } - c = c->origin; + MRB_CLASS_ORIGIN(c); while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; -- cgit v1.2.3 From 44eb1492bed2f9584623ec10ecf14cc46af4bf12 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 10 Sep 2015 22:24:10 +0900 Subject: freeze the hash key (fixes #2945) --- src/hash.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hash.c b/src/hash.c index 0bda2b48b..42b40482a 100644 --- a/src/hash.c +++ b/src/hash.c @@ -104,9 +104,11 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key)) - return mrb_str_dup(mrb, key); - else + if (mrb_string_p(key)) { + key = mrb_str_dup(mrb, key); + RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); + return key; + } else return key; } -- cgit v1.2.3 From 8256d77c7fe551011cc744ddb204ca20c4eea175 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 10 Sep 2015 22:50:01 +0900 Subject: avoid unnecessary string duplications by checking the frozen flag --- src/hash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hash.c b/src/hash.c index 42b40482a..ffb8bd931 100644 --- a/src/hash.c +++ b/src/hash.c @@ -104,12 +104,11 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key)) { + if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); - return key; - } else - return key; + } + return key; } #define KEY(key) mrb_hash_ht_key(mrb, key) -- cgit v1.2.3 From 698b3c925d757cd7113f9916db2dbb7e2eabf2f4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 10 Sep 2015 23:03:53 +0900 Subject: add Hash#rehash to handle key modification; ref #2945 --- mrblib/hash.rb | 23 +++++++++++++++++++++++ test/t/hash.rb | 9 +++++++++ 2 files changed, 32 insertions(+) diff --git a/mrblib/hash.rb b/mrblib/hash.rb index cb52c1ffe..48ac96e56 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -319,6 +319,29 @@ class Hash h end + ## + # call-seq: + # hsh.rehash -> hsh + # + # Rebuilds the hash based on the current hash values for each key. If + # values of key objects have changed since they were inserted, this + # method will reindex hsh. + # + # h = {"AAA" => "b"} + # h.keys[0].chop! + # h #=> {"AA"=>"b"} + # h["AA"] #=> nil + # h.rehash #=> {"AA"=>"b"} + # h["AA"] #=> "b" + # + def rehash + h = {} + self.each{|k,v| + h[k] = v + } + self.replace(h) + end + def __update(h) h.each_key{|k| self[k] = h[k]} self diff --git a/test/t/hash.rb b/test/t/hash.rb index eee7c7b6a..3196cc97a 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -342,3 +342,12 @@ assert('Hash#inspect') do assert_include ret, '"a"=>100' assert_include ret, '"d"=>400' end + +assert('Hash#rehash') do + h = {[:a] => "b"} + # hash key modified + h.keys[0][0] = :b + # h[[:b]] => nil + h.rehash + assert_equal("b", h[[:b]]) +end -- cgit v1.2.3 From 291265ec86e2b4a8d66b33be3e2d65fa6744da84 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 11 Sep 2015 00:15:01 +0900 Subject: Customize installation directory using INSTALL_DIR environment variable Previously, minirake installed several commands (e.g., mrbc) in repository locally under bin directory. But there was no knob for users to change this directory. It effectively made `make distcheck` fail if mruby was embedded into project managed by autotools. This change adds a way for the user to change installation directory by setting INSTALL_DIR environment variable. --- Rakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index 8a8912af5..3e03b1096 100644 --- a/Rakefile +++ b/Rakefile @@ -32,7 +32,7 @@ load "#{MRUBY_ROOT}/tasks/benchmark.rake" # generic build targets, rules task :default => :all -bin_path = "#{MRUBY_ROOT}/bin" +bin_path = ENV['INSTALL_DIR'] || "#{MRUBY_ROOT}/bin" FileUtils.mkdir_p bin_path, { :verbose => $verbose } depfiles = MRuby.targets['host'].bins.map do |bin| @@ -71,7 +71,7 @@ MRuby.each_target do |target| end if target == MRuby.targets['host'] - install_path = MRuby.targets['host'].exefile("#{MRUBY_ROOT}/bin/#{bin}") + install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}") file install_path => exec do |t| FileUtils.rm_f t.name, { :verbose => $verbose } @@ -80,7 +80,7 @@ MRuby.each_target do |target| depfiles += [ install_path ] elsif target == MRuby.targets['host-debug'] unless MRuby.targets['host'].gems.map {|g| g.bins}.include?([bin]) - install_path = MRuby.targets['host-debug'].exefile("#{MRUBY_ROOT}/bin/#{bin}") + install_path = MRuby.targets['host-debug'].exefile("#{bin_path}/#{bin}") file install_path => exec do |t| FileUtils.rm_f t.name, { :verbose => $verbose } -- cgit v1.2.3 From 8277e950eee4e8c6135eca281a7d5ca91077d2b4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Fri, 11 Sep 2015 11:12:03 +0900 Subject: Support windows locale Add mrb_utf8_from_locale, mrb_utf8_free, mrb_locale_from_utf8, mrb_locale_free. Just works for windows. --- include/mruby.h | 12 ++++++ mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 10 ++++- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 11 ++++- mrbgems/mruby-print/src/print.c | 13 +++--- src/string.c | 63 +++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 10 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index b4ec13fdc..dedbd0748 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -292,6 +292,18 @@ MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); #define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit)) +#ifdef _WIN32 +char* mrb_utf8_from_locale(const char *p, size_t len); +char* mrb_locale_from_utf8(const char *p, size_t len); +#define mrb_locale_free(p) free(p) +#define mrb_utf8_free(p) free(p) +#else +#define mrb_utf8_from_locale(p, l) (p) +#define mrb_locale_from_utf8(p, l) (p) +#define mrb_locale_free(p) +#define mrb_utf8_free(p) +#endif + MRB_API mrb_state* mrb_open(void); MRB_API mrb_state* mrb_open_allocf(mrb_allocf, void *ud); MRB_API mrb_state* mrb_open_core(mrb_allocf, void *ud); diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 0f3649a35..37fda352c 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -366,6 +366,8 @@ main(int argc, char **argv) ai = mrb_gc_arena_save(mrb); while (TRUE) { + char *utf8; + #ifndef ENABLE_READLINE print_cmdline(code_block_open); @@ -415,17 +417,21 @@ main(int argc, char **argv) strcpy(ruby_code, last_code_line); } + utf8 = mrb_utf8_from_locale(ruby_code, -1); + if (!utf8) abort(); + /* parse code */ parser = mrb_parser_new(mrb); if (parser == NULL) { fputs("create parser state error\n", stderr); break; } - parser->s = ruby_code; - parser->send = ruby_code + strlen(ruby_code); + parser->s = utf8; + parser->send = utf8 + strlen(utf8); parser->lineno = cxt->lineno; mrb_parser_parse(parser, cxt); code_block_open = is_code_block_open(parser); + mrb_utf8_free(utf8); if (code_block_open) { /* no evaluation of code */ diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 5ca744388..cc1ca3055 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -191,7 +191,11 @@ main(int argc, char **argv) ARGV = mrb_ary_new_capa(mrb, args.argc); for (i = 0; i < args.argc; i++) { - mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, args.argv[i])); + char* utf8 = mrb_utf8_from_locale(args.argv[i], -1); + if (utf8) { + mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8)); + mrb_utf8_free(utf8); + } } mrb_define_global_const(mrb, "ARGV", ARGV); @@ -222,7 +226,10 @@ main(int argc, char **argv) v = mrb_load_file_cxt(mrb, args.rfp, c); } else { - v = mrb_load_string_cxt(mrb, args.cmdline, c); + char* utf8 = mrb_utf8_from_locale(args.cmdline, -1); + if (!utf8) abort(); + v = mrb_load_string_cxt(mrb, utf8, c); + mrb_utf8_free(utf8); } mrbc_context_free(mrb, c); diff --git a/mrbgems/mruby-print/src/print.c b/mrbgems/mruby-print/src/print.c index 673ba2172..e7e21dd4b 100644 --- a/mrbgems/mruby-print/src/print.c +++ b/mrbgems/mruby-print/src/print.c @@ -1,17 +1,18 @@ #include "mruby.h" #include "mruby/string.h" #include +#include +#include static void printstr(mrb_state *mrb, mrb_value obj) { - char *s; - mrb_int len; - if (mrb_string_p(obj)) { - s = RSTRING_PTR(obj); - len = RSTRING_LEN(obj); - fwrite(s, len, 1, stdout); + char* ptr = mrb_locale_from_utf8(RSTRING_PTR(obj), RSTRING_LEN(obj)); + if (ptr) { + fwrite(ptr, strlen(ptr), 1, stdout); + mrb_locale_free(ptr); + } } } diff --git a/src/string.c b/src/string.c index 08caf3bae..e93fd4606 100644 --- a/src/string.c +++ b/src/string.c @@ -43,6 +43,69 @@ mrb_str_strlen(mrb_state *mrb, struct RString *s) return max; } +#ifdef _WIN32 +#include + +char* +mrb_utf8_from_locale(const char *str, size_t len) +{ + wchar_t* wcsp; + char* mbsp; + size_t mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = strlen(str); + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} + +char* +mrb_locale_from_utf8(const char *utf8, size_t len) +{ + wchar_t* wcsp; + char* mbsp; + size_t mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = strlen(utf8); + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} +#endif + static inline void resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) { -- cgit v1.2.3 From a085c04e3741825ab4c4ceda60b640e250ae56d5 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 12 Sep 2015 12:11:10 +0900 Subject: Don't crash if NULL is passed to mrb_close Sometimes it is very useful just return from mrb_close if NULL is passed as mrb. This is the same spirit of free(3), which just does nothing if NULL is passed. --- src/state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/state.c b/src/state.c index 2efd34334..bfd99e4c3 100644 --- a/src/state.c +++ b/src/state.c @@ -234,6 +234,7 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c) MRB_API void mrb_close(mrb_state *mrb) { + if (!mrb) return; if (mrb->atexit_stack_len > 0) { mrb_int i; for (i = mrb->atexit_stack_len; i > 0; --i) { -- cgit v1.2.3 From e8f88daa9c0486485072a1fb1c61a60ede0ff5c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 14 Sep 2015 15:56:54 +0900 Subject: instance_eval should set target_class; close #2936 target_class should be singleton class of the receiver --- mrbgems/mruby-eval/src/eval.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 8bfa2f112..dd5fd5024 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -235,12 +235,12 @@ f_instance_eval(mrb_state *mrb, mrb_value self) mrb_int len; char *file = NULL; mrb_int line = 1; + mrb_value cv; mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); c->ci->acc = CI_ACC_SKIP; - if (c->ci->target_class->tt == MRB_TT_ICLASS) { - c->ci->target_class = c->ci->target_class->c; - } + cv = mrb_singleton_class(mrb, self); + c->ci->target_class = mrb_class_ptr(cv); return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self); } else { -- cgit v1.2.3 From b88ca625ab44a063c9b105f06789446f791c8b3e Mon Sep 17 00:00:00 2001 From: takahashim Date: Wed, 16 Sep 2015 02:57:41 +0900 Subject: fix block variable in Hash#fetch --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 2 +- mrbgems/mruby-hash-ext/test/hash.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index c970b9d02..5056d0720 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -126,7 +126,7 @@ class Hash def fetch(key, none=NONE, &block) unless self.key?(key) if block - block.call + block.call(key) elsif none != NONE none else diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb index e1afdaaa3..4950ef354 100644 --- a/mrbgems/mruby-hash-ext/test/hash.rb +++ b/mrbgems/mruby-hash-ext/test/hash.rb @@ -75,6 +75,7 @@ assert('Hash#fetch') do assert_equal "feline", h.fetch("cat") assert_equal "mickey", h.fetch("mouse", "mickey") assert_equal "minny", h.fetch("mouse"){"minny"} + assert_equal "mouse", h.fetch("mouse"){|k| k} begin h.fetch("gnu") rescue => e -- cgit v1.2.3 From f1c23a0f75a4a38c5077e1df30af200f3700752f Mon Sep 17 00:00:00 2001 From: takahashim Date: Wed, 16 Sep 2015 18:50:03 +0900 Subject: support String#[]= with 3 args --- mrblib/string.rb | 49 ++++++++++++++++++++++++++++++++++++------- test/t/string.rb | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 05b13cb43..5765cff9b 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -154,13 +154,48 @@ class String end ## - # Modify +self+ by replacing the content of +self+ - # at the position +pos+ with +value+. - def []=(pos, value) - pos += self.length if pos < 0 - b = self[0, pos] - a = self[pos + 1..-1] - self.replace([b, value, a].join('')) + # Modify +self+ by replacing the content of +self+. + # The portion of the string affected is determined using the same criteria as +String#[]+. + def []=(*args) + anum = args.size + if anum == 2 + pos, value = args + if pos.kind_of? String + posnum = self.index(pos) + if posnum + b = self[0, posnum.to_i] + a = self[(posnum + pos.length)..-1] + self.replace([b, value, a].join('')) + return value + else + raise IndexError, "string not matched" + end + else + pos += self.length if pos < 0 + if pos < 0 || pos > self.length + raise IndexError, "index #{args[0]} out of string" + end + b = self[0, pos.to_i] + a = self[pos + 1..-1] + self.replace([b, value, a].join('')) + return value + end + elsif anum == 3 + pos, len, value = args + pos += self.length if pos < 0 + if pos < 0 || pos > self.length + raise IndexError, "index #{args[0]} out of string" + end + if len < 0 + raise IndexError, "negative length #{len}" + end + b = self[0, pos.to_i] + a = self[pos + len..-1] + self.replace([b, value, a].join('')) + return value + else + raise ArgumentError, "wrong number of arguments (#{anum} for 2..3)" + end end ## diff --git a/test/t/string.rb b/test/t/string.rb index 7326adce9..87aec0e21 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -122,6 +122,69 @@ assert('String#[] with Range') do assert_equal 'bc', j2 end +assert('String#[]=') do + # length of args is 1 + a = 'abc' + a[0] = 'X' + assert_equal 'Xbc', a + + b = 'abc' + b[-1] = 'X' + assert_equal 'abX', b + + c = 'abc' + assert_raise(IndexError) do + c[10] = 'X' + end + + d = 'abc' + assert_raise(IndexError) do + d[-10] = 'X' + end + + e = 'abc' + e[1.1] = 'X' + assert_equal 'aXc', e + + + # length of args is 2 + a1 = 'abc' + assert_raise(IndexError) do + a1[0, -1] = 'X' + end + + b1 = 'abc' + assert_raise(IndexError) do + b1[10, 0] = 'X' + end + + c1 = 'abc' + assert_raise(IndexError) do + c1[-10, 0] = 'X' + end + + d1 = 'abc' + d1[0, 0] = 'X' + assert_equal 'Xabc', d1 + + e1 = 'abc' + e1[1, 3] = 'X' + assert_equal 'aX', e1 + + # args is RegExp + # It will be tested in mrbgems. + + # args is String + a3 = 'abc' + a3['bc'] = 'X' + assert_equal a3, 'aX' + + b3 = 'abc' + assert_raise(IndexError) do + b3['XX'] = 'Y' + end +end + assert('String#capitalize', '15.2.10.5.7') do a = 'abc' a.capitalize -- cgit v1.2.3