diff options
126 files changed, 3306 insertions, 814 deletions
diff --git a/.travis.yml b/.travis.yml index f7be58c8a..bcfce3984 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,14 @@ -# no installation... +language: c + +matrix: + include: + - os: linux + sudo: 9000 + - os: osx + osx_image: xcod6.4 install: - - 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" @@ -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. 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. @@ -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" @@ -21,21 +22,17 @@ 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" -load "#{MRUBY_ROOT}/tasks/mrbgems_test.rake" -load "#{MRUBY_ROOT}/test/mrbtest.rake" - 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| @@ -74,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 } @@ -83,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 } @@ -117,9 +114,9 @@ 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? + run_test if test_enabled? end end diff --git a/build_config.rb b/build_config.rb index 3408f19a1..96b1d4684 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.enable_test + + conf.gembox 'default' +end + # Define cross build settings # MRuby::CrossBuild.new('32bit') do |conf| # toolchain :gcc 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/mruby.h.md b/doc/api/mruby.h.md index f537b6482..06bab2d56 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 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`| @@ -67,3 +69,149 @@ 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*); +``` +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) { + 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); +``` + +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){ + puts("Executing example command!"); + 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*); +``` + +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){ + 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); +} +``` + +### 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. + + +### mrb_value mrb_funcall + +```C +MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); +``` +Call existing ruby functions. diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md new file mode 100644 index 000000000..36c253cec --- /dev/null +++ b/doc/api/mruby/array.h.md @@ -0,0 +1,250 @@ +### 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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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/hash.h.md b/doc/api/mruby/hash.h.md new file mode 100644 index 000000000..fa12ea670 --- /dev/null +++ b/doc/api/mruby/hash.h.md @@ -0,0 +1,380 @@ +### 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 <stdio.h>
+#include <mruby.h>
+#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
+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:
+
+```Ruby
+a = {:da_key => 80}
+```
+
+```C
+#include <stdio.h>
+#include <mruby.h>
+#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
+```
+
+### 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:
+
+```Ruby
+a = {:da_key => 80}
+a[:da_key]
+```
+
+```C
+#include <stdio.h>
+#include <mruby.h>
+#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:
+
+```Ruby
+a = {:da_key1 => 80,:da_key2 => 90}
+a.delete(:da_key2)
+```
+
+```C
+#include <stdio.h>
+#include <mruby.h>
+#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_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 <stdio.h>
+#include <mruby.h>
+#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:
+
+```Ruby
+a = {:da_key1 => 80,:da_key2 => 90}
+a.clear
+```
+
+```C
+#include <stdio.h>
+#include <mruby.h>
+#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 {}
+```
diff --git a/doc/api/mruby/range.h.md b/doc/api/mruby/range.h.md new file mode 100644 index 000000000..188e6ede6 --- /dev/null +++ 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 <stdio.h>
+ #include <mruby.h>
+ #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
+```
diff --git a/doc/api/mruby/re.h.md b/doc/api/mruby/re.h.md new file mode 100644 index 000000000..f5cd2a71e --- /dev/null +++ b/doc/api/mruby/re.h.md @@ -0,0 +1,3 @@ +### Macros
+#### REGEXP_CLASS
+A string with the name of the REGEXP class.
diff --git a/doc/api/mruby/string.h.md b/doc/api/mruby/string.h.md new file mode 100644 index 000000000..7bf94df5b --- /dev/null +++ b/doc/api/mruby/string.h.md @@ -0,0 +1,91 @@ +## 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);
+```
+Adds to strings together.
+### mrb_ptr_to_str
+```C
+ mrb_value mrb_ptr_to_str(mrb_state *, void*);
+```
+Converts pointer into a Ruby string.
+### mrb_obj_as_string
+```C
+ 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.
+### 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 str1, 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.
diff --git a/doc/api/mruby/value.h.md b/doc/api/mruby/value.h.md new file mode 100644 index 000000000..fbf2dadf1 --- /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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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 <stdio.h>
+#include <mruby.h>
+#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/mruby/version.h.md b/doc/api/mruby/version.h.md new file mode 100644 index 000000000..f627b1da1 --- /dev/null +++ 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.
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: diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index 101177b13..f75231f71 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 omitted +``` + +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```. @@ -142,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 ``` @@ -189,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. diff --git a/include/mruby.h b/include/mruby.h index 6eb3af844..dedbd0748 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); @@ -203,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); @@ -250,16 +254,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) @@ -298,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/include/mruby/class.h b/include/mruby/class.h index 9d5260a24..85f3e12c6 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -48,8 +48,20 @@ 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_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) 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/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/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/include/mruby/error.h b/include/mruby/error.h index 52f6772bd..e3e2b25e2 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -24,11 +24,21 @@ 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); +/* 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); +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_int len, struct RClass **classes); + #if defined(__cplusplus) } /* extern "C" { */ #endif 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/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/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/include/mruby/version.h b/include/mruby/version.h index ea044d6da..c2a9b6306 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 \ diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 06609d9e7..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 extensional Enumerable module + # Use Enumerable module extension conf.gem :core => "mruby-enum-ext" - # Use extensional String class + # Use String class extension conf.gem :core => "mruby-string-ext" - # Use extensional Numeric class + # Use Numeric class extension conf.gem :core => "mruby-numeric-ext" - # Use extensional Array class + # Use Array class extension conf.gem :core => "mruby-array-ext" - # Use extensional Hash class + # Use Hash class extension conf.gem :core => "mruby-hash-ext" - # Use extensional Range class + # Use Range class extension conf.gem :core => "mruby-range-ext" - # Use extensional Proc class + # Use Proc class extension conf.gem :core => "mruby-proc-ext" - # Use extensional Symbol class + # Use Symbol class extension conf.gem :core => "mruby-symbol-ext" # Use Random class conf.gem :core => "mruby-random" - # Use extensional 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,6 +68,9 @@ MRuby::GemBox.new do |conf| # Generate mruby-strip command conf.gem :core => "mruby-bin-strip" - # Use extensional Kernel module + # Use Kernel module extension conf.gem :core => "mruby-kernel-ext" + + # Use mruby-compiler to build other mrbgems + conf.gem :core => "mruby-compiler" end 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/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake index e4b5938c7..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 = 'extensional Array class' + spec.summary = 'Array class extension' end 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-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') 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-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); diff --git a/mrbgems/mruby-bin-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index 98df38499..a74871d81 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -6,20 +6,28 @@ 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' + else + spec.linker.libraries << 'termcap' + end + end end end if RUBY_PLATFORM.include?('netbsd') 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" end spec.bins = %w(mirb) + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') end 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-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/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index f27f87a5d..2f507904a 100644 --- a/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; @@ -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/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 diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 44ad9bb06..cc1ca3055 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); } @@ -163,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); } @@ -196,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); @@ -227,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/bintest/mrbc.rb b/mrbgems/mruby-compiler/bintest/mrbc.rb index b016378a1..b016378a1 100644 --- a/bintest/mrbc.rb +++ b/mrbgems/mruby-compiler/bintest/mrbc.rb diff --git a/src/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 222dec9b6..3853814ec 100644 --- a/src/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--; + s->iseq[s->pc] = i; + } if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { /* skip swapping OP_MOVE */ return 0; @@ -406,7 +411,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)) @@ -957,13 +973,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; @@ -1008,6 +1017,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 */ @@ -1622,8 +1633,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; @@ -1912,7 +1929,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)); @@ -1921,7 +1938,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)); @@ -1930,7 +1947,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)); @@ -1943,7 +1960,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; @@ -1952,7 +1971,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BACK_REF: - { + if (val) { char buf[2] = { '$' }; mrb_value str; int sym; @@ -1966,7 +1985,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); @@ -2651,13 +2670,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; diff --git a/src/keywords b/mrbgems/mruby-compiler/core/keywords index 9cb86608c..9cb86608c 100644 --- a/src/keywords +++ b/mrbgems/mruby-compiler/core/keywords diff --git a/src/lex.def b/mrbgems/mruby-compiler/core/lex.def index ea456a843..58e302965 100644 --- a/src/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 <[email protected]>." #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" diff --git a/src/node.h b/mrbgems/mruby-compiler/core/node.h index 532a8323a..532a8323a 100644 --- a/src/node.h +++ b/mrbgems/mruby-compiler/core/node.h diff --git a/src/parse.y b/mrbgems/mruby-compiler/core/parse.y index 5b17649a9..097d63ac4 100644 --- a/src/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 = $<stack>4; + CMDARG_LEXPOP(); } | keyword_if expr_value then compstmt @@ -2941,7 +2942,7 @@ backref : tNTH_REF | tBACK_REF ; -superclass : term +superclass : /* term */ { $$ = 0; } @@ -2953,12 +2954,12 @@ superclass : term expr_value term { $$ = $3; - } + } /* | error term { yyerrok; $$ = 0; - } + } */ ; f_arglist : '(' f_args rparen @@ -3604,10 +3605,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* @@ -4204,7 +4208,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 +4459,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 +4765,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 +4780,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) { @@ -4802,6 +4806,7 @@ parser_yylex(parser_state *p) case ')': case ']': p->paren_nest--; + /* fall through */ case '}': COND_LEXPOP(); CMDARG_LEXPOP(); @@ -5133,6 +5138,7 @@ parser_yylex(parser_state *p) pushback(p, c); return '$'; } + /* fall through */ case '0': tokadd(p, '$'); } @@ -5157,10 +5163,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 +5182,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-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-enum-ext/mrbgem.rake b/mrbgems/mruby-enum-ext/mrbgem.rake index 0c9d88fa2..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 = 'extensional Enumerable module' + spec.summary = 'Enumerable module extension' end 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-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..911fde0be --- /dev/null +++ b/mrbgems/mruby-error/src/exception.c @@ -0,0 +1,100 @@ +#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; + result = mrb_obj_value(mrb->exc); + 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, 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_int len, struct RClass **classes) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + mrb_bool error_matched = FALSE; + mrb_int i; + + 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; + + for (i = 0; i < len; ++i) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), classes[i])) { + error_matched = TRUE; + break; + } + } + + 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..2a943aaae --- /dev/null +++ b/mrbgems/mruby-error/test/exception.c @@ -0,0 +1,59 @@ +#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; + struct RClass *cls[1]; + mrb_get_args(mrb, "oo", &b, &r); + cls[0] = E_TYPE_ERROR; + return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, 1, cls); +} + +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..0bbc2a0e7 --- /dev/null +++ b/mrbgems/mruby-error/test/exception.rb @@ -0,0 +1,55 @@ +assert 'mrb_protect' do + # no failure in protect returns [result, false] + assert_equal ['test', false] do + ExceptionTest.mrb_protect { '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 + 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 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/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 { 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 <code>resume</code> the reciever wouldn't be pushed to call + * Transfers control to receiver fiber of the method call. + * Unlike <code>resume</code> 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 diff --git a/mrbgems/mruby-hash-ext/mrbgem.rake b/mrbgems/mruby-hash-ext/mrbgem.rake index 663de2166..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 = 'extensional 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-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index ea5e6bc1b..5056d0720 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -119,14 +119,14 @@ class Hash # # <em>produces:</em> # - # prog.rb:2:in `fetch': key not found (KeyError) + # prog.rb:2:in 'fetch': key not found (KeyError) # from prog.rb:2 # 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 diff --git a/mrbgems/mruby-kernel-ext/mrbgem.rake b/mrbgems/mruby-kernel-ext/mrbgem.rake index ab610c02b..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 = 'extensional 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 3d8be7cd5..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 = 'extensional 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 91a6e7ff1..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 = 'extensional Object class' + spec.summary = 'Object class extension' end 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 <stdio.h> +#include <string.h> +#include <stdlib.h> 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/mrbgems/mruby-proc-ext/mrbgem.rake b/mrbgems/mruby-proc-ext/mrbgem.rake index 41d964bd9..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 = 'extensional Proc class' + spec.summary = 'Proc class extension' end 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 diff --git a/mrbgems/mruby-range-ext/mrbgem.rake b/mrbgems/mruby-range-ext/mrbgem.rake index bcf3de202..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 = 'extensional Range class' + spec.summary = 'Range class extension' end diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index d88e242c6..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) { @@ -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-string-ext/mrbgem.rake b/mrbgems/mruby-string-ext/mrbgem.rake index 688589933..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 = 'extensional String class' + spec.summary = 'String class extension' end 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 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 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); 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 <code>Struct</code> 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 - * ``<i>Customer</i>Class,'' and we'll show an example instance of that - * class as ``<i>Customer</i>Inst.'' + * "<i>Customer</i>Class," and we'll show an example instance of that + * class as "<i>Customer</i>Inst." * * In the descriptions that follow, the parameter <i>symbol</i> refers * to a symbol, which is either a quoted string or a diff --git a/mrbgems/mruby-symbol-ext/mrbgem.rake b/mrbgems/mruby-symbol-ext/mrbgem.rake index b937a0742..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 = 'extensional Symbol class' + spec.summary = 'Symbol class extension' end diff --git a/test/README.md b/mrbgems/mruby-test/README.md index fa4b91e3a..fa4b91e3a 100644 --- a/test/README.md +++ b/mrbgems/mruby-test/README.md diff --git a/test/driver.c b/mrbgems/mruby-test/driver.c index 7f0633723..7f0633723 100644 --- a/test/driver.c +++ b/mrbgems/mruby-test/driver.c diff --git a/test/init_mrbtest.c b/mrbgems/mruby-test/init_mrbtest.c index 1e2ba92bd..1e2ba92bd 100644 --- a/test/init_mrbtest.c +++ b/mrbgems/mruby-test/init_mrbtest.c diff --git a/tasks/mrbgems_test.rake b/mrbgems/mruby-test/mrbgem.rake index 0ee508360..b6b247ff6 100644 --- a/tasks/mrbgems_test.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -1,13 +1,46 @@ -MRuby.each_target do - gem_table = gems.generate_gem_table self +MRuby::Gem::Specification.new('mruby-test') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby test' - gems.each do |g| + build.bins << 'mrbtest' + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') + + clib = "#{build_dir}/mrbtest.c" + mlib = clib.ext(exts.object) + 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 + + gem_table = build.gems.generate_gem_table build + + build.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) + 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, __FILE__, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t| + 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) @@ -91,4 +124,51 @@ MRuby.each_target do end end end + + 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 => [build.mrbcfile, init] 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' + 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) {] + build.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/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b377f3e33..c18ac7568 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,12 +4,17 @@ ** See Copyright Notice in mruby.h */ +#include <math.h> #include <stdio.h> #include <time.h> #include "mruby.h" #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 <sys/time.h> #endif @@ -200,20 +205,23 @@ 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)); } - tm->usec = (time_t)((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; } - 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 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 diff --git a/mrblib/array.rb b/mrblib/array.rb index bd8d5930f..65dd0d665 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 @@ -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 @@ -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,10 +70,10 @@ class Array self.clear if size > 0 - self[size - 1] = nil # allocate + self[size - 1] = nil # allocate idx = 0 - while(idx < size) + while idx < size self[idx] = (block)? block.call(idx): obj idx += 1 end @@ -146,7 +144,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 <code>Array#<=></code> if and only if they have + # "equal" according to <code>Array#<=></code> 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. # @@ -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,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 diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 6bf219283..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 @@ -402,8 +382,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 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 diff --git a/mrblib/hash.rb b/mrblib/hash.rb index e7c51fb1f..48ac96e56 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) @@ -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 <i>hsh</i>. + # + # 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/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..6e4c5027f 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 @@ -100,18 +100,18 @@ 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? 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 @@ -165,16 +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/mrblib/range.rb b/mrblib/range.rb index 1ec9ac508..5e5fd9bdc 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -26,29 +26,23 @@ 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 - while((val <=> last) < 0) + while (val <=> last) < 0 block.call(val) 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 diff --git a/mrblib/string.rb b/mrblib/string.rb index 1d9ea9e6a..5765cff9b 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 @@ -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 @@ -46,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 ## @@ -76,7 +106,9 @@ 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) + 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])) else @@ -93,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 ## @@ -106,7 +134,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 +146,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 @@ -126,23 +154,54 @@ class String end ## - # Modify +self+ by replacing the content of +self+ - # at the position +pos+ with +value+. - def []=(pos, value) - if pos < 0 - pos += self.length + # 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 - b = self[0, pos] - 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 diff --git a/src/array.c b/src/array.c index 48dc1ff10..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(); } @@ -88,15 +87,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,18 +289,19 @@ 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; mrb_get_args(mrb, "a", &ptr, &blen); - ary = mrb_ary_new_capa(mrb, a1->len + blen); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE - blen < a1->len) { + 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); array_copy(a2->ptr + a1->len, ptr, blen); a2->len = a1->len + blen; - return ary; + return mrb_obj_value(a2); } static void @@ -342,7 +339,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; @@ -351,9 +347,10 @@ 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); - - ary = mrb_ary_new_capa(mrb, a1->len * times); - a2 = mrb_ary_ptr(ary); + if (ARY_MAX_SIZE / times < a1->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + a2 = ary_new_capa(mrb, a1->len * times); ptr = a2->ptr; while (times--) { array_copy(ptr, a1->ptr, a1->len); @@ -361,7 +358,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self) a2->len += a1->len; } - return ary; + return mrb_obj_value(a2); } static mrb_value @@ -388,11 +385,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; @@ -404,7 +398,7 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self) } b->len = a->len; } - return ary; + return mrb_obj_value(b); } MRB_API void @@ -1036,7 +1030,7 @@ 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, "|S!", &sep); return mrb_ary_join(mrb, ary, sep); } @@ -1047,7 +1041,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(); } @@ -1063,7 +1056,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/class.c b/src/class.c index 3246564ec..c3c3e0b8f 100644 --- a/src/class.c +++ b/src/class.c @@ -76,7 +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->mt = 0; + sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { c = (struct RClass*)o; @@ -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)); } @@ -174,12 +188,20 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) } 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) { struct RClass * c; if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); + 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), @@ -198,7 +220,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); } @@ -232,15 +254,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); @@ -305,7 +319,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 @@ -317,8 +331,10 @@ 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; + MRB_CLASS_ORIGIN(c); + h = c->mt; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); @@ -429,12 +445,12 @@ to_sym(mrb_state *mrb, mrb_value ss) ---------------------------------------------------------------------------------------------- o: Object [mrb_value] C: class/module [mrb_value] - S: String [mrb_value] - A: Array [mrb_value] - H: Hash [mrb_value] - 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 [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] @@ -519,6 +535,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_str(mrb, *sp++); i++; @@ -530,6 +554,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++; @@ -541,6 +573,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++; @@ -555,6 +595,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); @@ -569,6 +618,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); @@ -585,6 +642,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); @@ -670,6 +736,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; @@ -753,47 +827,130 @@ boot_defclass(mrb_state *mrb, struct RClass *super) return c; } -MRB_API void -mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +static void +boot_initmod(mrb_state *mrb, struct RClass *mod) { - struct RClass *ins_pos; + mod->mt = kh_init(mt, mrb); +} + +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; + } + MRB_CLASS_ORIGIN(m); + ic->iv = m->iv; + ic->mt = m->mt; + ic->super = super; + if (m->tt == MRB_TT_ICLASS) { + ic->c = m->c; + } else { + ic->c = m; + } + return ic; +} + +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 = find_origin(c)->mt; - ins_pos = c; while (m) { - struct RClass *p = c, *ic; int superclass_seen = 0; - if (c->mt && c->mt == m->mt) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); - } - while (p) { - if (c != p && p->tt == MRB_TT_CLASS) { - superclass_seen = 1; - } - else if (p->mt == m->mt) { - if (p->tt == MRB_TT_ICLASS && !superclass_seen) { - ins_pos = p; + if (m->flags & MRB_FLAG_IS_PREPENDED) + goto skip; + + if (klass_mt && klass_mt == m->mt) + return -1; + + p = c->super; + while(p) { + if (p->tt == MRB_TT_ICLASS) { + if (p->mt == m->mt) { + if (!superclass_seen) { + ins_pos = p; // move insert point + } + goto skip; } - goto skip; + } else if (p->tt == MRB_TT_CLASS) { + if (!search_super) break; + superclass_seen = 1; } 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->mt = m->mt; - ic->iv = m->iv; - ic->super = ins_pos->super; + + ic = include_class_new(mrb, m, ins_pos->super); ins_pos->super = ic; - mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); + mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ins_pos->super); ins_pos = ic; skip: m = m->super; } + return 0; +} + +MRB_API void +mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + int changed = include_module_at(mrb, c, find_origin(c), m, 1); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); + } +} + +MRB_API void +mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + struct RClass *origin; + int changed = 0; + + 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->super = c->super; + c->super = origin; + origin->mt = c->mt; + c->mt = kh_init(mt, mrb); + 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) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected"); + } +} + +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<argc; i++) { + mrb_check_type(mrb, argv[i], MRB_TT_MODULE); + } + while (argc--) { + mrb_funcall(mrb, argv[argc], "prepend_features", 1, klass); + mrb_funcall(mrb, argv[argc], "prepended", 1, klass); + } + + return klass; } static mrb_value @@ -867,15 +1024,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->flags & MRB_FLAG_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -900,11 +1054,15 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + MRB_CLASS_ORIGIN(origin); 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 != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } } c = c->super; } @@ -916,10 +1074,11 @@ static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; - - mrb_get_args(mrb, "&", &b); + struct RClass *m = mrb_class_ptr(mod); + 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, mrb_class_ptr(mod)); + mrb_yield_with_class(mrb, b, 1, &mod, mod, m); } return mod; } @@ -1168,11 +1327,11 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * call-seq: * class.new(args, ...) -> obj * - * Calls <code>allocate</code> to create a new object of - * <i>class</i>'s class, then invokes that object's - * <code>initialize</code> method, passing it <i>args</i>. - * This is the method that ends up getting called whenever - * an object is constructed using .new. + * Creates a new object of <i>class</i>'s class, then + * invokes that object's <code>initialize</code> method, + * passing it <i>args</i>. This is the method that ends + * up getting called whenever an object is constructed using + * `.new`. * */ @@ -1236,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->super; + c = find_origin(c)->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->super; + c = find_origin(c)->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1256,6 +1415,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: @@ -1295,27 +1479,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(); } @@ -1469,8 +1635,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->mt = kh_init(mt, mrb); - + boot_initmod(mrb, m); return m; } @@ -1537,10 +1702,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, ">"); @@ -1652,7 +1817,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); } } @@ -1829,18 +1994,19 @@ 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 = find_origin(c)->mt; khiter_t k; if (h) { 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; } } - 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); } @@ -2069,6 +2235,9 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ + mrb_define_method(mrb, mod, "prepend", mrb_mod_prepend, MRB_ARGS_ANY()); + mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "include", mrb_mod_include, MRB_ARGS_ANY()); /* 15.2.2.4.27 */ mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */ mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ @@ -2085,6 +2254,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)); 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()); diff --git a/src/dump.c b/src/dump.c index d9410ec18..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 @@ -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)); @@ -979,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; } diff --git a/src/error.c b/src/error.c index a800f77f9..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); @@ -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); } @@ -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) { @@ -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); diff --git a/src/fmt_fp.c b/src/fmt_fp.c index ef2f19dd5..b27ebd6e9 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) -static long double -frexpl (long double x, int *eptr) -{ - return frexp(x, eptr); -} +#if ((defined(__CYGWIN__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) +#undef frexpl +#define frexpl frexp #endif static int @@ -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; diff --git a/src/hash.c b/src/hash.c index 0bda2b48b..ffb8bd931 100644 --- a/src/hash.c +++ b/src/hash.c @@ -104,10 +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 - return 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; } #define KEY(key) mrb_hash_ht_key(mrb, key) diff --git a/src/kernel.c b/src/kernel.c index d1e10a7f8..225f7fa54 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -240,14 +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)); } - clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -269,6 +267,21 @@ 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->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; } @@ -330,6 +343,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); @@ -366,6 +382,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); @@ -635,13 +654,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->flags & MRB_FLAG_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + 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 { 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 { 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 <<EOS -#define __STDC_CONSTANT_MACROS -#define __STDC_LIMIT_MACROS - -extern "C" { -#include "#{MRUBY_ROOT}/#{t.prerequisites.first}" -} - - -#{v == 'error'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} -EOS - end - end - - file objfile(src) => 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 <<EOS -#define __STDC_CONSTANT_MACROS -#define __STDC_LIMIT_MACROS - -extern "C" { -#include "#{t.prerequisites.first}" -} -EOS - end - end - file objfile("#{current_build_dir}/y.tab") => ["#{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/numeric.c b/src/numeric.c index 8b6ec4c88..1a3c903f0 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); } @@ -110,8 +111,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 - * ``<code>NaN</code>'', ``<code>Infinity</code>'', and - * ``<code>-Infinity</code>''. + * "<code>NaN</code>", "<code>Infinity</code>", and + * "<code>-Infinity</code>". */ static mrb_value @@ -436,7 +437,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 +452,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; @@ -819,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); } @@ -831,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/src/object.c b/src/object.c index c5fb74575..2e0bd245f 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 <i>obj</i>. The default * <code>to_s</code> 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 @@ -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"); } + MRB_CLASS_ORIGIN(c); while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; diff --git a/src/print.c b/src/print.c index b43936b13..077fa4f06 100644 --- a/src/print.c +++ b/src/print.c @@ -8,49 +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_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 + 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 @@ -59,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 @@ -69,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); } diff --git a/src/proc.c b/src/proc.c index 4cb9ffe18..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) { @@ -200,7 +201,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 +215,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 ? -(ma + pa + 1) : ma + pa; + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; return mrb_fixnum_value(arity); } 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/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) { diff --git a/src/string.c b/src/string.c index 128578afd..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 <windows.h> + +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) { @@ -75,9 +138,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 +191,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) { @@ -1100,7 +1181,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of <i>str</i> 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" */ @@ -1345,6 +1426,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); @@ -1703,7 +1785,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) * * If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If * <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is - * split on whitespace as if ` ' were specified. + * split on whitespace as if ' ' were specified. * * If the <i>limit</i> parameter is omitted, trailing null fields are * suppressed. If <i>limit</i> is a positive number, at most that number of @@ -1715,10 +1797,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"] @@ -1846,7 +1926,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) \ @@ -1929,7 +2009,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 == '_') { @@ -1966,9 +2046,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) { @@ -1987,7 +2067,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); @@ -2004,12 +2085,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); @@ -2058,6 +2139,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}; @@ -2078,7 +2160,6 @@ bad: return d; } if (*end) { - char buf[DBL_DIG * 4 + 10]; char *n = buf; char *e = buf + sizeof(buf) - 1; char prev = 0; @@ -2212,7 +2293,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) * * Returns a copy of <i>str</i> 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" */ @@ -2367,10 +2448,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) */ @@ -2515,4 +2596,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()); } diff --git a/src/variable.c b/src/variable.c index 3e451df05..efe6fad12 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)); } } @@ -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; } 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)); @@ -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) @@ -723,6 +724,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) { @@ -1030,7 +1033,7 @@ RETRY_TRY_BLOCK: mrb_callinfo *ci = mrb->c->ci; int n, eidx = ci->eidx; - for (n=0; n<a && eidx > ci[-1].eidx; n++) { + for (n=0; n<a && (ci == mrb->c->cibase || eidx > ci[-1].eidx); n++) { ecall(mrb, --eidx); ARENA_RESTORE(mrb, ai); } @@ -1074,9 +1077,21 @@ 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_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) { mrb_ary_unshift(mrb, regs[a+1], sym); } @@ -1471,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; @@ -1483,6 +1495,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; @@ -2125,33 +2140,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+pre<len; idx++) { + regs[a+idx] = ary->ptr[pre+idx]; } - else { - regs[a++] = mrb_ary_new_capa(mrb, 0); - for (idx=0; idx+pre<len; idx++) { - regs[a+idx] = ary->ptr[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); diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index e6e17e182..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 @@ -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") @@ -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? "#{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] } } + 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 diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 66608286d..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) @@ -80,11 +80,13 @@ 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 @cxx_exception_disabled = false + @enable_bintest = false + @enable_test = false @toolchains = [] MRuby.targets[@name] = self @@ -92,6 +94,9 @@ module MRuby MRuby::Build.current = MRuby.targets[@name] MRuby.targets[@name].instance_eval(&block) + + build_mrbc_exec if name == 'host' + build_mrbtest if test_enabled? end def enable_debug @@ -119,6 +124,32 @@ 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| + FileUtils.mkdir_p File.dirname t.name + IO.write t.name, <<EOS +#define __STDC_CONSTANT_MACROS +#define __STDC_LIMIT_MACROS + +extern "C" { +#include "#{src}" +} + +#{src == "#{MRUBY_ROOT}/src/error.c"? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} +EOS + end + + file obj => 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 +173,28 @@ module MRuby 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 + 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 @@ -213,10 +264,10 @@ module MRuby 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 + run_bintest if bintest_enabled? end def run_bintest @@ -246,6 +297,10 @@ module MRuby 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) @@ -257,7 +312,7 @@ module MRuby 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/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 diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake index dbbade487..896aeb147 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -52,10 +52,33 @@ 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, "--depth 1" + 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] 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]}" @@ -71,6 +94,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}" diff --git a/tasks/toolchains/androideabi.rake b/tasks/toolchains/androideabi.rake index 61881ca31..272e802f7 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'] || DEFAULT_GCC_VERSION + CLANG_VERSION = ENV['CLANG_VERSION'] || DEFAULT_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 @@ -109,8 +111,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 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 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 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/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 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 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 diff --git a/test/t/module.rb b/test/t/module.rb index 9852328ce..4bde20fbe 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 @@ -474,6 +494,286 @@ 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 + + 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 + + # mruby shouldn't be affected by this since there is + # no visibility control (yet) + assert('Module#prepend public') do + assert_nothing_raised('ruby/ruby #8846') do + Class.new.prepend(Module.new) + end + end + + assert('Module#prepend inheritance') do + bug6654 = '[ruby-core:45914]' + 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 + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + #end + + bug8357 = '[ruby-core:54736] [Bug #8357]' + 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 + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + #end + + bug8357 = '[ruby-core:54742] [Bug #8357]' + assert_kind_of(b, c.new, bug8357) + end + + 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 'Module#prepend + #singleton_methods' do + o = Object.new + o.singleton_class.class_eval {prepend Module.new} + assert_equal([], o.singleton_methods) + end + + assert 'Module#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 'Module#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 + + 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 } + 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 '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 'cyclic Module#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 + + # mruby has no visibility control + assert 'Module#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 'Module#prepend inherited visibility' 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 'Module#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 'Module#prepend super in alias' do + skip "super does not currently work in aliased methods" + 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_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 '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 class") + end + + 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 'Module#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 'Module#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 +# @!endgroup prepend + assert('Module#to_s') do module Test4to_sModules end @@ -533,3 +833,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 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 diff --git a/test/t/string.rb b/test/t/string.rb index 63e4af000..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 @@ -254,6 +317,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 'ab<X>cd<X>ef', s.gsub('X', '<\\&>') + assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\0>') + assert_equal 'ab<ab>cd<abXcd>ef', s.gsub('X', '<\\`>') + assert_equal 'ab<cdXef>cd<ef>ef', s.gsub('X', '<\\\'>') +end + assert('String#gsub!', '15.2.10.5.19') do a = 'abcabc' a.gsub!('b', 'B') @@ -416,6 +488,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 'ab<X>cdXef', s.sub('X', '<\\&>') + assert_equal 'ab<X>cdXef', s.sub('X', '<\\0>') + assert_equal 'ab<ab>cdXef', s.sub('X', '<\\`>') + assert_equal 'ab<cdXef>cdXef', s.sub('X', '<\\\'>') +end + assert('String#sub!', '15.2.10.5.37') do a = 'abcabc' a.sub!('b', 'B') @@ -524,3 +605,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 + diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 5ce4e0a63..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 @@ -219,6 +219,35 @@ 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('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 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..4ee6d752b 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| @@ -20,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| @@ -31,6 +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 |
