diff options
67 files changed, 1381 insertions, 444 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,9 +26,6 @@ load "#{MRUBY_ROOT}/mrblib/mrblib.rake" load "#{MRUBY_ROOT}/tasks/mrbgems.rake" load "#{MRUBY_ROOT}/tasks/libmruby.rake" -load "#{MRUBY_ROOT}/tasks/mrbgems_test.rake" -load "#{MRUBY_ROOT}/test/mrbtest.rake" - load "#{MRUBY_ROOT}/tasks/benchmark.rake" ############################## @@ -117,9 +114,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..d3c1ebc1f 100644 --- a/build_config.rb +++ b/build_config.rb @@ -21,6 +21,7 @@ MRuby::Build.new do |conf| # include the default GEMs conf.gembox 'default' + conf.gem :core => 'mruby-eval' # C compiler settings # conf.cc do |cc| @@ -105,7 +106,17 @@ MRuby::Build.new('host-debug') do |conf| conf.gem :core => "mruby-bin-debugger" # bintest - # conf.enable_bintest + conf.enable_bintest +end + +MRuby::Build.new('test') do |conf| + toolchain :gcc + + enable_debug + conf.enable_bintest + conf.enable_test + + conf.gembox 'default' end # Define cross build settings diff --git a/doc/api/mruby.h.md b/doc/api/mruby.h.md index 8862fee2c..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`| @@ -118,7 +120,7 @@ mrb_value example_method(mrb_state* mrb, mrb_value self){ void mrb_example_gem_init(mrb_state* mrb) { struct RClass *example_class; example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); - mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); + mrb_define_method(mrb, example_class, "example_method", example_method, MRB_ARGS_NONE()); } void mrb_example_gem_final(mrb_state* mrb) { diff --git a/doc/api/mruby/array.h.md b/doc/api/mruby/array.h.md index e1fb0003d..36c253cec 100644 --- a/doc/api/mruby/array.h.md +++ b/doc/api/mruby/array.h.md @@ -12,28 +12,27 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/array.h" // Needs the array header.
#include "mruby/compile.h"
-
int main(int argc, char *argv[])
-{
- mrb_value new_ary; // Declare variable.
- mrb_state *mrb = mrb_open();
- if (!mrb) { /* handle error */ }
- FILE *fp = fopen("test.rb","r");
- new_ary = mrb_ary_new(mrb);
- mrb_value obj = mrb_load_file(mrb,fp);
- mrb_funcall(mrb, obj, "method_name", 1, new_ary);
- fclose(fp);
- mrb_close(mrb);
- return 0;
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb);
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
}
```
test.rb
```Ruby
class Example_Class
- def method_name(a)
- puts a
- puts a.class
- end
+ def method_name(a)
+ puts a
+ puts a.class
+ end
end
Example_Class.new
```
@@ -52,32 +51,32 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h"
int main(int argc, char *argv[])
-{
- mrb_value new_ary; // Declare variable.
- mrb_int random_value1 = 70; // Initialize variable
- mrb_int random_value2 = 60; // Initialize variable
- mrb_state *mrb = mrb_open();
- if (!mrb) { /* handle error */ }
- FILE *fp = fopen("test.rb","r");
- new_ary = mrb_ary_new(mrb); // Initialize ruby array.
- /* Pushes the fixnum value from random_value1 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
- /* Pushes the fixnum value from random_value2 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
- mrb_value obj = mrb_load_file(mrb,fp);
- mrb_funcall(mrb, obj, "method_name", 1, new_ary);
- fclose(fp);
- mrb_close(mrb);
- return 0;
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
}
```
test.rb
```Ruby
class Example_Class
- def method_name(a)
- puts a
- puts a.class
- end
+ def method_name(a)
+ puts a
+ puts a.class
+ end
end
Example_Class.new
```
@@ -103,37 +102,37 @@ called pop_ary that will return the array alone(just to be clean) and you should #include "mruby/compile.h"
int main(int argc, char *argv[])
-{
- mrb_value new_ary; // Declare variable.
- mrb_int random_value1 = 70; // Initialize variable
- mrb_int random_value2 = 60; // Initialize variable
- mrb_state *mrb = mrb_open();
- if (!mrb) { /* handle error */ }
- FILE *fp = fopen("test.rb","r");
- new_ary = mrb_ary_new(mrb); // Initialize ruby array.
- /* Pushes the fixnum value from random_value1 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
- /* Pushes the fixnum value from random_value2 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
- mrb_value obj = mrb_load_file(mrb,fp);
- mrb_funcall(mrb, obj, "method_name", 1, new_ary);
- mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60.
- mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results.
- fclose(fp);
- mrb_close(mrb);
- return 0;
+{
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "method_name", 1, new_ary);
+ mrb_ary_pop(mrb, new_ary); // Pops the last element of the array. In this case 60.
+ mrb_funcall(mrb, obj, "pop_ary", 1, new_ary); // Calls the method again to show the results.
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
}
```
test.rb
```Ruby
class Example_Class
- def method_name(a)
- puts a
- puts a.class
- end
- def pop_ary(a)
- puts a
- end
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+ def pop_ary(a)
+ puts a
+ end
end
Example_Class.new
```
@@ -158,35 +157,35 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h"
int main(int argc, char *argv[])
-{
- mrb_value ary_ref; // Declare variable.
- mrb_value new_ary; // Declare variable.
- mrb_int random_value1 = 70; // Initialize variable
- mrb_int random_value2 = 60; // Initialize variable
- mrb_state *mrb = mrb_open();
- if (!mrb) { /* handle error */ }
- FILE *fp = fopen("test.rb","r");
- new_ary = mrb_ary_new(mrb); // Initialize ruby array.
- /* Pushes the fixnum value from random_value1 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
- /* Pushes the fixnum value from random_value2 to the new_ary instance. */
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
- ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1.
- mrb_value obj = mrb_load_file(mrb,fp);
- /* Passing the value from ary_ref to the method method_name.*/
- mrb_funcall(mrb, obj, "method_name", 1, ary_ref);
- fclose(fp);
- mrb_close(mrb);
- return 0;
+{
+ mrb_value ary_ref; // Declare variable.
+ mrb_value new_ary; // Declare variable.
+ mrb_int random_value1 = 70; // Initialize variable
+ mrb_int random_value2 = 60; // Initialize variable
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb); // Initialize ruby array.
+ /* Pushes the fixnum value from random_value1 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ /* Pushes the fixnum value from random_value2 to the new_ary instance. */
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ ary_ref = mrb_ary_ref(mrb, new_ary, 1); // Gets the value of new_ary's second element at index 1.
+ mrb_value obj = mrb_load_file(mrb,fp);
+ /* Passing the value from ary_ref to the method method_name.*/
+ mrb_funcall(mrb, obj, "method_name", 1, ary_ref);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
}
```
test.rb
```Ruby
class Example_Class
- def method_name(a)
- puts a
- puts a.class
- end
+ def method_name(a)
+ puts a
+ puts a.class
+ end
end
Example_Class.new
```
@@ -211,36 +210,36 @@ In this example we read from a Ruby file inside C. The Ruby code will print what #include "mruby/compile.h"
int main(int argc, char *argv[])
-{
- mrb_value new_ary;
- mrb_value ary_obj;
- mrb_int random_value1 = 70;
- mrb_int random_value2 = 60;
- mrb_state *mrb = mrb_open();
- if (!mrb) { /* handle error */ }
- FILE *fp = fopen("test.rb","r");
- new_ary = mrb_ary_new(mrb);
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
- mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
- /* Sets the fixnum value of 7 to the second index of the array.*/
- mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7));
- mrb_value obj = mrb_load_file(mrb,fp);
- mrb_funcall(mrb, obj, "before_after", 1, new_ary);
- fclose(fp);
- mrb_close(mrb);
- return 0;
+{
+ mrb_value new_ary;
+ mrb_value ary_obj;
+ mrb_int random_value1 = 70;
+ mrb_int random_value2 = 60;
+ mrb_state *mrb = mrb_open();
+ if (!mrb) { /* handle error */ }
+ FILE *fp = fopen("test.rb","r");
+ new_ary = mrb_ary_new(mrb);
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value1));
+ mrb_ary_push(mrb, new_ary, mrb_fixnum_value(random_value2));
+ /* Sets the fixnum value of 7 to the second index of the array.*/
+ mrb_ary_set(mrb, new_ary, 2, mrb_fixnum_value(7));
+ mrb_value obj = mrb_load_file(mrb,fp);
+ mrb_funcall(mrb, obj, "before_after", 1, new_ary);
+ fclose(fp);
+ mrb_close(mrb);
+ return 0;
}
```
test.rb
```Ruby
class Example_Class
- def method_name(a)
- puts a
- puts a.class
- end
- def before_after(a)
- puts a
- end
+ def method_name(a)
+ puts a
+ puts a.class
+ end
+ def before_after(a)
+ puts a
+ end
end
Example_Class.new
```
diff --git a/doc/api/mruby/hash.h.md b/doc/api/mruby/hash.h.md 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/re.h.md b/doc/api/mruby/re.h.md new file mode 100644 index 000000000..01e18c6a5 --- /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 index f3ae2d421..fbf2dadf1 100644 --- a/doc/api/mruby/value.h.md +++ b/doc/api/mruby/value.h.md @@ -38,10 +38,10 @@ main(void) test.rb
```Ruby
class My_Class
- def method_name(s)
- puts s
- puts s.class
- end
+ def method_name(s)
+ puts s
+ puts s.class
+ end
end
a = My_Class.new
```
@@ -86,10 +86,10 @@ main(void) test.rb
```Ruby
class My_Class
- def method_name(s)
- puts s
- puts s.class
- end
+ def method_name(s)
+ puts s
+ puts s.class
+ end
end
a = My_Class.new
```
@@ -134,10 +134,10 @@ main(void) test.rb
```Ruby
class My_Class
- def method_name(s)
- puts s
- puts s.class
- end
+ def method_name(s)
+ puts s
+ puts s.class
+ end
end
a = My_Class.new
```
@@ -181,10 +181,10 @@ main(void) test.rb
```Ruby
class My_Class
- def method_name(s)
- puts s
- puts s.class
- end
+ def method_name(s)
+ puts s
+ puts s.class
+ end
end
a = My_Class.new
```
@@ -229,10 +229,10 @@ main(void) test.rb
```Ruby
class My_Class
- def method_name(s)
- puts s
- puts s.class
- end
+ def method_name(s)
+ puts s
+ puts s.class
+ end
end
a = My_Class.new
```
diff --git a/doc/api/mruby/version.h.md b/doc/api/mruby/version.h.md new file mode 100644 index 000000000..daf87077d --- /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/mrbgems/README.md b/doc/mrbgems/README.md index e0c60daf2..f75231f71 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -198,17 +198,21 @@ end In case your GEM has more complex build requirements you can use the following options additionally inside of your GEM specification: -* `spec.cflags` (C compiler flags) -* `spec.mruby_cflags` (global C compiler flags for everything) -* `spec.mruby_ldflags` (global linker flags for everything) -* `spec.mruby_libs` (global libraries for everything) -* `spec.mruby_includes` (global includes for everything) +* `spec.cc.flags` (C compiler flags) +* `spec.cc.defines` (C compiler defines) +* `spec.cc.include_paths` (C compiler include paths) +* `spec.linker.flags` (Linker flags) +* `spec.linker.libraries` (Linker libraries) +* `spec.linker.library_paths` (Linker additional library path) +* `spec.bins` (Generate binary file) * `spec.rbfiles` (Ruby files to compile) * `spec.objs` (Object files to compile) * `spec.test_rbfiles` (Ruby test files for integration into mrbtest) * `spec.test_objs` (Object test files for integration into mrbtest) * `spec.test_preload` (Initialization files for mrbtest) +You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker. + ### include_paths and dependency Your GEM can export include paths to another GEMs that depends on your GEM. 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 282be0a24..e3e2b25e2 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -29,6 +29,16 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va /* declaration for fail method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); +/* functions defined in mruby-error mrbgem */ +MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state); +MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t ensure, mrb_value e_data); +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/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/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/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-mirb/mrbgem.rake b/mrbgems/mruby-bin-mirb/mrbgem.rake index 7d45409c9..a74871d81 100644 --- a/mrbgems/mruby-bin-mirb/mrbgem.rake +++ b/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -20,6 +20,9 @@ MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| spec.linker.libraries << 'edit' else spec.linker.libraries << 'readline' + if spec.build.cc.search_header_path 'curses.h' + spec.linker.libraries << 'ncurses' + end end elsif spec.build.cc.search_header_path 'linenoise.h' spec.cc.defines << "ENABLE_LINENOISE" diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index f27f87a5d..2f507904a 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -119,10 +119,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) args->flags |= DUMP_DEBUG_INFO; break; case 'E': - args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); + args->flags = DUMP_ENDIAN_BIG | (args->flags & ~DUMP_ENDIAN_MASK); break; case 'e': - args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); + args->flags = DUMP_ENDIAN_LIL | (args->flags & ~DUMP_ENDIAN_MASK); break; case 'h': return -1; @@ -161,8 +161,7 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) static void cleanup(mrb_state *mrb, struct mrbc_args *args) { - if (args->outfile) - mrb_free(mrb, (void*)args->outfile); + mrb_free(mrb, (void*)args->outfile); mrb_close(mrb); } diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 141ea151b..5ca744388 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -159,10 +159,9 @@ cleanup(mrb_state *mrb, struct _args *args) { if (args->rfp && args->rfp != stdin) fclose(args->rfp); - if (args->cmdline && !args->fname) + if (!args->fname) mrb_free(mrb, args->cmdline); - if (args->argv) - mrb_free(mrb, args->argv); + mrb_free(mrb, args->argv); mrb_close(mrb); } diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index cefde8b7b..3853814ec 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -188,6 +188,11 @@ genop_peep(codegen_scope *s, mrb_code i, int val) if (val) break; switch (c0) { case OP_MOVE: + if (GETARG_A(i) == GETARG_A(i0)) { + /* skip overriden OP_MOVE */ + s->pc--; + 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)) @@ -1001,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 */ diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b057cac17..097d63ac4 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -2154,6 +2154,7 @@ primary : literal $$ = new_lambda(p, $3, $5); local_unnest(p); p->cmdarg_stack = $<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 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-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index de216f69f..81b48b10d 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -73,7 +73,7 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) { char buf[64], *b = buf + sizeof buf; mrb_int num = mrb_fixnum(x); - unsigned long val = (unsigned long)num; + uint64_t val = (uint64_t)num; char d; if (base != 2) { diff --git a/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/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/mrblib/array.rb b/mrblib/array.rb index 933f822db..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 @@ -50,9 +50,7 @@ class Array def collect!(&block) return to_enum :collect! unless block_given? - self.each_index{|idx| - self[idx] = block.call(self[idx]) - } + self.each_index { |idx| self[idx] = block.call(self[idx]) } self end @@ -72,7 +70,7 @@ class Array self.clear if size > 0 - self[size - 1] = nil # allocate + self[size - 1] = nil # allocate idx = 0 while idx < size @@ -158,14 +156,11 @@ class Array len = self.size n = other.size - if len > n - len = n - end + len = n if len > n i = 0 while i < len n = (self[i] <=> other[i]) - return n if n == nil - return n if n != 0 + return n if n.nil? || n != 0 i += 1 end len = self.size - other.size @@ -185,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/numeric.rb b/mrblib/numeric.rb index cf608b04b..6e4c5027f 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -100,7 +100,7 @@ module Integral # Calls the given block from +self+ to +num+ # incremented by +step+ (default 1). # - def step(num, step=1, &block) + def step(num, step = 1, &block) raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block_given? @@ -165,16 +165,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 64fa0cb6c..5e5fd9bdc 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -26,9 +26,7 @@ class Range return self end - unless val.respond_to? :succ - raise TypeError, "can't iterate" - end + raise TypeError, "can't iterate" unless val.respond_to? :succ return self if (val <=> last) > 0 @@ -37,18 +35,14 @@ class Range val = val.succ end - if not exclude_end? and (val <=> last) == 0 - block.call(val) - end + block.call(val) if !exclude_end? && (val <=> last) == 0 self end # redefine #hash 15.3.1.3.15 def hash h = first.hash ^ last.hash - if self.exclude_end? - h += 1 - end + h += 1 if self.exclude_end? h end end diff --git a/mrblib/string.rb b/mrblib/string.rb index ee097ad6d..05b13cb43 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -80,12 +80,8 @@ class String # ISO 15.2.10.5.19 def gsub!(*args, &block) str = self.gsub(*args, &block) - if str != self - self.replace(str) - self - else - nil - end + return nil if str == self + self.replace(str) end ## @@ -111,6 +107,7 @@ class String def sub(*args, &block) if args.size == 2 pre, post = split(args[0], 2) + return self unless post # The sub target wasn't found in the string pre + args[1].__sub_replace(pre, args[0], post) + post elsif args.size == 1 && block split(args[0], 2).join(block.call(args[0])) @@ -128,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 ## @@ -164,20 +157,16 @@ class String # Modify +self+ by replacing the content of +self+ # at the position +pos+ with +value+. def []=(pos, value) - if pos < 0 - pos += self.length - end + pos += self.length if pos < 0 b = self[0, pos] - a = self[pos+1..-1] + a = self[pos + 1..-1] self.replace([b, value, a].join('')) end ## # ISO 15.2.10.5.3 def =~(re) - if re.respond_to? :to_str - raise TypeError, "type mismatch: String given" - end + raise TypeError, "type mismatch: String given" if re.respond_to? :to_str re =~ self end diff --git a/src/array.c b/src/array.c index 0a99040c0..2622ee528 100644 --- a/src/array.c +++ b/src/array.c @@ -19,7 +19,6 @@ static inline mrb_value ary_elt(mrb_value ary, mrb_int offset) { - if (RARRAY_LEN(ary) == 0) return mrb_nil_value(); if (offset < 0 || RARRAY_LEN(ary) <= offset) { return mrb_nil_value(); } diff --git a/src/class.c b/src/class.c index 90c463579..462ab40b5 100644 --- a/src/class.c +++ b/src/class.c @@ -438,12 +438,12 @@ to_sym(mrb_state *mrb, mrb_value ss) ---------------------------------------------------------------------------------------------- o: Object [mrb_value] C: class/module [mrb_value] - S: String [mrb_value] when ! follows the value may be nil - A: Array [mrb_value] - H: Hash [mrb_value] - s: String [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] @@ -530,7 +530,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (*format == '!') { format++; - if (mrb_nil_p(*sp)) { + if (i < argc && mrb_nil_p(*sp)) { *p = *sp++; i++; break; @@ -547,6 +547,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++; @@ -558,6 +566,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++; @@ -572,6 +588,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); @@ -586,6 +611,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); @@ -602,6 +635,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); @@ -687,6 +729,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; @@ -1648,10 +1698,10 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: - mrb_str_append(mrb, str, mrb_inspect(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); break; default: - mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); + mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v)); break; } return mrb_str_cat_lit(mrb, str, ">"); diff --git a/src/dump.c b/src/dump.c index 2f2e5edcb..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 @@ -978,12 +978,8 @@ error_exit: mrb_free(mrb, *bin); *bin = NULL; } - if (lv_syms) { - mrb_free(mrb, lv_syms); - } - if (filenames) { - mrb_free(mrb, filenames); - } + mrb_free(mrb, lv_syms); + mrb_free(mrb, filenames); return result; } diff --git a/src/error.c b/src/error.c index 20c63bd43..359e5737b 100644 --- a/src/error.c +++ b/src/error.c @@ -152,7 +152,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) mrb_str_append(mrb, str, line); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); mrb_str_cat_lit(mrb, str, " ("); } mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); @@ -165,7 +165,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc) str = mrb_str_new_cstr(mrb, cname); mrb_str_cat_lit(mrb, str, ": "); if (append_mesg) { - mrb_str_append(mrb, str, mesg); + mrb_str_cat_str(mrb, str, mesg); } else { mrb_str_cat_cstr(mrb, str, cname); @@ -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 b467435a3..b27ebd6e9 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -90,7 +90,7 @@ fmt_u(uint32_t x, char *s) typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; #endif -#if ((defined(__CYGWIN32__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) +#if ((defined(__CYGWIN__) || defined(__NetBSD__) || defined(mips)) && !defined(__linux__)) || defined(__android__) #undef frexpl #define frexpl frexp #endif 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/numeric.c b/src/numeric.c index b9aef51d9..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); } @@ -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/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/string.c b/src/string.c index 45ba38c9d..08caf3bae 100644 --- a/src/string.c +++ b/src/string.c @@ -75,9 +75,18 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_frozen(mrb_state *mrb, struct RString *s) +{ + if (RSTR_FROZEN_P(s)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); + } +} + MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { + check_frozen(mrb, s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -119,6 +128,15 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } +static mrb_value +mrb_str_freeze(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + + RSTR_SET_FROZEN_FLAG(s); + return str; +} + MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -1345,6 +1363,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { long len; + check_frozen(mrb, s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -1844,7 +1863,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) const char *p; char sign = 1; int c, uscore; - unsigned long n = 0; + uint64_t n = 0; mrb_int val; #define conv_digit(c) \ @@ -1964,9 +1983,9 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) } n *= base; n += c; - } - if (n > MRB_INT_MAX) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str)); + if (n > MRB_INT_MAX) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str)); + } } val = n; if (badcheck) { @@ -2366,10 +2385,10 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) } MRB_API mrb_value -mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2) +mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { str2 = mrb_str_to_str(mrb, str2); - return mrb_str_cat_str(mrb, str, str2); + return mrb_str_cat_str(mrb, str1, str2); } #define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ @@ -2514,4 +2533,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); + + mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } diff --git a/src/variable.c b/src/variable.c index 1b2ad56a7..efe6fad12 100644 --- a/src/variable.c +++ b/src/variable.c @@ -609,7 +609,7 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) else { ins = mrb_inspect(mrb, v); } - mrb_str_append(mrb, str, ins); + mrb_str_cat_str(mrb, str, ins); return 0; } 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) @@ -1032,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); } @@ -1485,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; @@ -1497,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; diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index 04a9c39f0..d13e7733f 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -130,7 +130,7 @@ module MRuby end def define_gem_init_builder - file objfile("#{build_dir}/gem_init") => "#{build_dir}/gem_init.c" + file objfile("#{build_dir}/gem_init") => [ "#{build_dir}/gem_init.c", File.join(dir, "mrbgem.rake") ] file "#{build_dir}/gem_init.c" => [build.mrbcfile, __FILE__] + [rbfiles].flatten do |t| FileUtils.mkdir_p build_dir generate_gem_init("#{build_dir}/gem_init.c") diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 947b4ba77..6863b635a 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -46,7 +46,7 @@ module MRuby include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir attr_reader :libmruby, :gems, :toolchains - attr_writer :enable_bintest + attr_writer :enable_bintest, :enable_test COMPILERS = %w(cc cxx objc asm) COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) @@ -85,6 +85,8 @@ module MRuby @build_mrbtest_lib_only = false @cxx_abi_enabled = false @cxx_exception_disabled = false + @enable_bintest = false + @enable_test = false @toolchains = [] MRuby.targets[@name] = self @@ -94,6 +96,7 @@ module MRuby MRuby.targets[@name].instance_eval(&block) build_mrbc_exec if name == 'host' + build_mrbtest if test_enabled? end def enable_debug @@ -127,8 +130,8 @@ module MRuby obj = objfile(cxx_src) if obj.nil? file cxx_src => [src, __FILE__] do |t| - File.open(t.name, 'w') do |f| - f.write <<EOS + FileUtils.mkdir_p File.dirname t.name + IO.write t.name, <<EOS #define __STDC_CONSTANT_MACROS #define __STDC_LIMIT_MACROS @@ -136,9 +139,8 @@ extern "C" { #include "#{src}" } -#{File.basename(src) == 'error.c'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} +#{src == "#{MRUBY_ROOT}/src/error.c"? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''} EOS - end end file obj => cxx_src do |t| @@ -171,6 +173,18 @@ EOS MRUBY_ROOT end + def enable_test + @enable_test = true + end + + def test_enabled? + @enable_test + end + + def build_mrbtest + gem :core => 'mruby-test' + end + def build_mrbc_exec gem :core => 'mruby-bin-mrbc' end @@ -250,10 +264,10 @@ EOS def run_test puts ">>> Test #{name} <<<" - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" puts - run_bintest if @enable_bintest + run_bintest if bintest_enabled? end def run_bintest @@ -298,7 +312,7 @@ EOS end def run_test - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") if (@test_runner.command == nil) puts "You should run #{mrbtest} on target device." puts diff --git a/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 26990a380..896aeb147 100644 --- a/tasks/mruby_build_gem.rake +++ b/tasks/mruby_build_gem.rake @@ -59,7 +59,7 @@ module MRuby git.run_pull mgem_list_dir, mgem_list_url if $pull_gems else FileUtils.mkdir_p mgem_list_dir - git.run_clone mgem_list_dir, mgem_list_url + git.run_clone mgem_list_dir, mgem_list_url, "--depth 1" end require 'yaml' @@ -76,6 +76,9 @@ module MRuby if params[:core] gemdir = "#{root}/mrbgems/#{params[:core]}" + elsif params[:path] + require 'pathname' + gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}" elsif params[:git] url = params[:git] gemdir = "#{gem_clone_dir}/#{url.match(/([-\w]+)(\.[-\w]+|)$/).to_a[1]}" diff --git a/tasks/toolchains/androideabi.rake b/tasks/toolchains/androideabi.rake index 7cdb9e43a..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 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/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/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/string.rb b/test/t/string.rb index ee6fe0848..7326adce9 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -542,3 +542,11 @@ assert('String#each_byte') do assert_equal bytes1, bytes2 end + +assert('String#freeze') do + str = "hello" + str.freeze + + assert_raise(RuntimeError) { str.upcase! } +end + diff --git a/test/t/syntax.rb b/test/t/syntax.rb index dc1a4a3b9..fb6ffe408 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -1,6 +1,6 @@ assert('__FILE__') do - file = __FILE__ - assert_true 'test/t/syntax.rb' == file || 'test\t\syntax.rb' == file + file = __FILE__.split('test/')[1] + assert_true 't/syntax.rb' == file || 't\syntax.rb' == file end assert('__LINE__') do diff --git a/travis_config.rb b/travis_config.rb index 2b4059cf1..4ee6d752b 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -22,6 +22,7 @@ MRuby::Build.new do |conf| c.defines += %w(MRB_GC_FIXED_ARENA) end conf.enable_bintest + conf.enable_test end MRuby::Build.new('cxx_abi') do |conf| @@ -33,6 +34,7 @@ MRuby::Build.new('cxx_abi') do |conf| c.defines += %w(MRB_GC_FIXED_ARENA) end conf.enable_bintest + conf.enable_test enable_cxx_abi |
