Merge branch 'master' into android.rake-ndk-clang

This commit is contained in:
Felix Jones
2017-02-16 13:33:46 +00:00
113 changed files with 3603 additions and 1116 deletions
-8
View File
@@ -16,11 +16,3 @@ addons:
env: MRUBY_CONFIG=travis_config.rb
script: "./minirake all test"
notifications:
# Update mruby-head installed on Travis CI so other projects can test against it.
webhooks:
urls:
- "https://rubies.travis-ci.org/rebuild/mruby-head"
on_success: always
on_failure: never
+1
View File
@@ -34,3 +34,4 @@ Original Authors "mruby developers" are:
Yuichi Osawa
Terence Lee
Zachary Scott
Tomasz Dąbrowski
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 mruby developers
Copyright (c) 2017 mruby developers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
+4 -2
View File
@@ -16,8 +16,10 @@ MRuby::Build.new do |conf|
# g.cc.flags << '-g' # append cflags in this gem
# end
# conf.gem 'examples/mrbgems/c_and_ruby_extension_example'
# conf.gem :github => 'masuidrive/mrbgems-example', :checksum_hash => '76518e8aecd131d047378448ac8055fa29d974a9'
# conf.gem :git => 'git@github.com:masuidrive/mrbgems-example.git', :branch => 'master', :options => '-v'
# conf.gem :core => 'mruby-eval'
# conf.gem :mgem => 'mruby-io'
# conf.gem :github => 'iij/mruby-io'
# conf.gem :git => 'git@github.com:iij/mruby-io.git', :branch => 'master', :options => '-v'
# include the default GEMs
conf.gembox 'default'
+82
View File
@@ -0,0 +1,82 @@
MRuby::Build.new do |conf|
# Gets set by the VS command prompts.
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
toolchain :visualcpp
else
toolchain :gcc
end
enable_debug
# include the default GEMs
conf.gembox 'default'
end
# Cross Compiling configuration for RX630
# http://gadget.renesas.com/
#
# Requires gnurx_v14.03
MRuby::CrossBuild.new("RX630") do |conf|
toolchain :gcc
# Linux
BIN_PATH = "/usr/share/gnurx_v14.03_elf-1/bin"
conf.cc do |cc|
cc.command = "#{BIN_PATH}/rx-elf-gcc"
cc.flags = "-Wall -g -O2 -flto -mcpu=rx600 -m64bit-doubles"
cc.compile_options = "%{flags} -o %{outfile} -c %{infile}"
#configuration for low memory environment
cc.defines << %w(MRB_USE_FLOAT)
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(MRB_USE_IV_SEGLIST)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
cc.defines << %w(MRB_GC_STRESS)
cc.defines << %w(MRB_DISABLE_STDIO) #if you dont need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
end
conf.cxx do |cxx|
cxx.command = conf.cc.command.dup
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.linker do |linker|
linker.command="#{BIN_PATH}/rx-elf-ld"
end
conf.archiver do |archiver|
archiver.command = "#{BIN_PATH}/rx-elf-ar"
archiver.archive_options = 'rcs %{outfile} %{objs}'
end
#no executables
conf.bins = []
#do not build executable test
conf.build_mrbtest_lib_only
#disable C++ exception
conf.disable_cxx_exception
#gems from core
conf.gem :core => "mruby-sprintf"
conf.gem :core => "mruby-print"
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-enum-ext"
conf.gem :core => "mruby-numeric-ext"
#light-weight regular expression
#conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master"
#Arduino API
#conf.gem :github =>"kyab/mruby-arduino", :branch => "master"
end
@@ -0,0 +1,26 @@
MRuby::Build.new do |conf|
# Gets set by the VS command prompts.
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
toolchain :visualcpp
else
toolchain :gcc
end
enable_debug
# include the default GEMs
conf.gembox 'default'
end
# Requires Android NDK r13 or later.
MRuby::CrossBuild.new('android-arm64-v8a') do |conf|
params = {
:arch => 'arm64-v8a',
:platform => 'android-24',
:toolchain => :clang,
}
toolchain :android, params
conf.gembox 'default'
end
@@ -0,0 +1,26 @@
MRuby::Build.new do |conf|
# Gets set by the VS command prompts.
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
toolchain :visualcpp
else
toolchain :gcc
end
enable_debug
# include the default GEMs
conf.gembox 'default'
end
# Requires Android NDK r13 or later.
MRuby::CrossBuild.new('android-armeabi') do |conf|
params = {
:arch => 'armeabi',
:platform => 'android-24',
:toolchain => :clang,
}
toolchain :android, params
conf.gembox 'default'
end
+17
View File
@@ -7,6 +7,23 @@
#ifndef MRUBYCONF_H
#define MRUBYCONF_H
#include <limits.h>
#include <stdint.h>
/* architecture selection: */
/* specify -DMRB_32BIT or -DMRB_64BIT to override */
#if !defined(MRB_32BIT) && !defined(MRB_64BIT)
#if UINT64_MAX == SIZE_MAX
#define MRB_64BIT
#else
#define MRB_32BIT
#endif
#endif
#if defined(MRB_32BIT) && defined(MRB_64BIT)
#error Cannot build for 32 and 64 bit architecture at the same time
#endif
/* configuration options: */
/* add -DMRB_USE_FLOAT to use float instead of double for floating point numbers */
//#define MRB_USE_FLOAT
+76 -41
View File
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
** Copyright (c) mruby developers 2010-2016
** Copyright (c) mruby developers 2010-2017
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
@@ -28,11 +28,49 @@
#ifndef MRUBY_H
#define MRUBY_H
#ifdef __cplusplus
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#ifdef __cplusplus
#ifndef SIZE_MAX
#ifdef __SIZE_MAX__
#define SIZE_MAX __SIZE_MAX__
#else
#define SIZE_MAX std::numeric_limits<size_t>::max()
#endif
#endif
#endif
#ifdef MRB_DEBUG
#include <assert.h>
#define mrb_assert(p) assert(p)
#define mrb_assert_int_fit(t1,n,t2,max) assert((n)>=0 && ((sizeof(n)<=sizeof(t2))||(n<=(t1)(max))))
#else
#define mrb_assert(p) ((void)0)
#define mrb_assert_int_fit(t1,n,t2,max) ((void)0)
#endif
#if __STDC_VERSION__ >= 201112L
#define mrb_static_assert(exp, str) _Static_assert(exp, str)
#else
#define mrb_static_assert(exp, str) mrb_assert(exp)
#endif
#include "mrbconf.h"
#ifdef MRB_USE_FLOAT
#define MRB_FLOAT_EPSILON FLT_EPSILON
#else
#define MRB_FLOAT_EPSILON DBL_EPSILON
#endif
#include "mruby/common.h"
#include <mruby/value.h>
#include <mruby/gc.h>
@@ -183,6 +221,10 @@ typedef struct mrb_state {
struct RClass *eException_class;
struct RClass *eStandardError_class;
struct RObject *nomem_err; /* pre-allocated NoMemoryError */
struct RObject *stack_err; /* pre-allocated SysStackError */
#ifdef MRB_GC_FIXED_ARENA
struct RObject *arena_err; /* pre-allocated arena overfow error */
#endif
void *ud; /* auxiliary data */
@@ -392,7 +434,7 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_
*
* mrb_value
* mrb_example_method(mrb_state *mrb){
* return mrb_str_new_cstr(mrb, "example");
* return mrb_str_new_lit(mrb, "example");
* }
*
* void
@@ -435,7 +477,7 @@ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*);
*
* mrb_value
* mrb_example_method(mrb_state *mrb){
* return mrb_str_new_cstr(mrb, "example");
* return mrb_str_new_lit(mrb, "example");
* }
*
* void
@@ -566,6 +608,14 @@ MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name);
*/
MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
/**
* Gets a exception class.
* @param [mrb_state*] mrb The current mruby state.
* @param [const char *] name The name of the class.
* @return [struct RClass *] A reference to the class.
*/
MRB_API struct RClass * mrb_exc_get(mrb_state *mrb, const char *name);
/**
* Returns an mrb_bool. True if inner class was defined, and false if the inner class was not defined.
*
@@ -578,10 +628,10 @@ MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
* example_outer = mrb_define_module(mrb, "ExampleOuter");
*
* example_inner = mrb_define_class_under(mrb, example_outer, "ExampleInner", mrb->object_class);
* cd = mrb_class_under_defined(mrb, example_outer, "ExampleInner");
* cd = mrb_class_defined_under(mrb, example_outer, "ExampleInner");
*
* // If mrb_class_under_defined returns 1 then puts "True"
* // If mrb_class_under_defined returns 0 then puts "False"
* // If mrb_class_defined_under returns 1 then puts "True"
* // If mrb_class_defined_under returns 0 then puts "False"
* if (cd == 1){
* puts("True");
* }
@@ -595,7 +645,7 @@ MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
* @param [const char *] name A string representing the name of the inner class.
* @return [mrb_bool] A boolean value.
*/
MRB_API mrb_bool mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name);
MRB_API mrb_bool mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name);
/**
* Gets a child class.
@@ -658,7 +708,7 @@ MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char
*
* example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class);
* mrb_define_method(mrb, example_class, "example_method", exampleMethod, MRB_ARGS_NONE());
* mid = mrb_intern_str(mrb, mrb_str_new_cstr(mrb, "example_method" ));
* mid = mrb_intern_str(mrb, mrb_str_new_lit(mrb, "example_method" ));
* obj_resp = mrb_obj_respond_to(mrb, example_class, mid); // => 1(true in Ruby world)
*
* // If mrb_obj_respond_to returns 1 then puts "True"
@@ -846,7 +896,7 @@ MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...);
* mrb_state *mrb = mrb_open();
*
* if (!mrb) { }
* mrb_sym m_sym = mrb_intern_cstr(mrb, "method_name"); // Symbol for method.
* mrb_sym m_sym = mrb_intern_lit(mrb, "method_name"); // Symbol for method.
*
* FILE *fp = fopen("test.rb","r");
* mrb_value obj = mrb_load_file(mrb,fp);
@@ -874,7 +924,7 @@ MRB_API mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int
* :pizza # => :pizza
*
* // C style:
* mrb_sym m_sym = mrb_intern_cstr(mrb, "pizza"); // => :pizza
* mrb_sym m_sym = mrb_intern_lit(mrb, "pizza"); // => :pizza
* @param [mrb_state*] mrb_state* The current mruby state.
* @param [const char*] const char* The name of the method.
* @return [mrb_sym] mrb_sym A symbol.
@@ -1050,23 +1100,22 @@ MRB_API void mrb_print_error(mrb_state *mrb);
+ those E_* macros requires mrb_state* variable named mrb.
+ exception objects obtained from those macros are local to mrb
*/
#define E_RUNTIME_ERROR (mrb_class_get(mrb, "RuntimeError"))
#define E_TYPE_ERROR (mrb_class_get(mrb, "TypeError"))
#define E_ARGUMENT_ERROR (mrb_class_get(mrb, "ArgumentError"))
#define E_INDEX_ERROR (mrb_class_get(mrb, "IndexError"))
#define E_RANGE_ERROR (mrb_class_get(mrb, "RangeError"))
#define E_NAME_ERROR (mrb_class_get(mrb, "NameError"))
#define E_NOMETHOD_ERROR (mrb_class_get(mrb, "NoMethodError"))
#define E_SCRIPT_ERROR (mrb_class_get(mrb, "ScriptError"))
#define E_SYNTAX_ERROR (mrb_class_get(mrb, "SyntaxError"))
#define E_LOCALJUMP_ERROR (mrb_class_get(mrb, "LocalJumpError"))
#define E_REGEXP_ERROR (mrb_class_get(mrb, "RegexpError"))
#define E_SYSSTACK_ERROR (mrb_class_get(mrb, "SystemStackError"))
#define E_RUNTIME_ERROR (mrb_exc_get(mrb, "RuntimeError"))
#define E_TYPE_ERROR (mrb_exc_get(mrb, "TypeError"))
#define E_ARGUMENT_ERROR (mrb_exc_get(mrb, "ArgumentError"))
#define E_INDEX_ERROR (mrb_exc_get(mrb, "IndexError"))
#define E_RANGE_ERROR (mrb_exc_get(mrb, "RangeError"))
#define E_NAME_ERROR (mrb_exc_get(mrb, "NameError"))
#define E_NOMETHOD_ERROR (mrb_exc_get(mrb, "NoMethodError"))
#define E_SCRIPT_ERROR (mrb_exc_get(mrb, "ScriptError"))
#define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError"))
#define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError"))
#define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError"))
#define E_NOTIMP_ERROR (mrb_class_get(mrb, "NotImplementedError"))
#define E_FLOATDOMAIN_ERROR (mrb_class_get(mrb, "FloatDomainError"))
#define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError"))
#define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError"))
#define E_KEY_ERROR (mrb_class_get(mrb, "KeyError"))
#define E_KEY_ERROR (mrb_exc_get(mrb, "KeyError"))
MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
@@ -1098,6 +1147,7 @@ MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id);
MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid);
MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c);
MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func);
/*
@@ -1119,7 +1169,7 @@ MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value
*
* @mrbgem mruby-fiber
*/
#define E_FIBER_ERROR (mrb_class_get(mrb, "FiberError"))
#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError"))
/* memory pool implementation */
typedef struct mrb_pool mrb_pool;
@@ -1135,21 +1185,6 @@ MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
MRB_API void mrb_show_version(mrb_state *mrb);
MRB_API void mrb_show_copyright(mrb_state *mrb);
#ifdef MRB_DEBUG
#include <assert.h>
#define mrb_assert(p) assert(p)
#define mrb_assert_int_fit(t1,n,t2,max) assert((n)>=0 && ((sizeof(n)<=sizeof(t2))||(n<=(t1)(max))))
#else
#define mrb_assert(p) ((void)0)
#define mrb_assert_int_fit(t1,n,t2,max) ((void)0)
#endif
#if __STDC_VERSION__ >= 201112L
#define mrb_static_assert(exp, str) _Static_assert(exp, str)
#else
#define mrb_static_assert(exp, str) mrb_assert(exp)
#endif
MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
MRB_END_DECL
+129 -7
View File
@@ -54,14 +54,60 @@ MRB_API mrb_value mrb_ary_new_capa(mrb_state*, mrb_int);
* Array.new
*
* @param mrb The mruby state reference.
* @return The initialized array
* @return The initialized array.
*/
MRB_API mrb_value mrb_ary_new(mrb_state *mrb);
/*
* Initializes a new array with initial values
*
* Equivalent to:
*
* Array[value1, value2, ...]
*
* @param mrb The mruby state reference.
* @param size The numer of values.
* @param vals The actual values.
* @return The initialized array.
*/
MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals);
/*
* Initializes a new array with two initial values
*
* Equivalent to:
*
* Array[car, cdr]
*
* @param mrb The mruby state reference.
* @param car The first value.
* @param cdr The second value.
* @return The initialized array.
*/
MRB_API mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr);
MRB_API void mrb_ary_concat(mrb_state*, mrb_value, mrb_value);
MRB_API mrb_value mrb_ary_splat(mrb_state*, mrb_value);
/*
* Concatenate two arrays. The target array will be modified
*
* Equivalent to:
* ary.concat(other)
*
* @param mrb The mruby state reference.
* @param self The target array.
* @param other The array that will be concatenated to self.
*/
MRB_API void mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other);
/*
* Create an array from the input. It tries calling to_a on the
* value. If value does not respond to that, it creates a new
* array with just this value.
*
* @param mrb The mruby state reference.
* @param value The value to change into an array.
* @return An array representation of value.
*/
MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value value);
/*
* Pushes value into array.
@@ -84,8 +130,8 @@ MRB_API void mrb_ary_push(mrb_state *mrb, mrb_value array, mrb_value value);
* ary.pop
*
* @param mrb The mruby state reference.
* @param ary The array from which the value will be poped.
* @return The poped value.
* @param ary The array from which the value will be popped.
* @return The popped value.
*/
MRB_API mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary);
@@ -117,14 +163,81 @@ MRB_API mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n);
*/
MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val);
MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value a, mrb_value b);
/*
* Replace the array with another array
*
* Equivalent to:
*
* ary.replace(other)
*
* @param mrb The mruby state reference
* @param self The target array.
* @param other The array to replace it with.
*/
MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other);
MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
/*
* Unshift an element into an array
*
* Equivalent to:
*
* ary.unshift(item)
*
* @param mrb The mruby state reference.
* @param self The target array.
* @param item The item to unshift.
*/
MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item);
MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
/*
* Shifts the first element from the array.
*
* Equivalent to:
*
* ary.shift
*
* @param mrb The mruby state reference.
* @param self The array from which the value will be shifted.
* @return The shifted value.
*/
MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self);
/*
* Removes all elements from this array
*
* Equivalent to:
*
* ary.clear
*
* @param mrb The mruby state reference.
* @param self The target array.
* @return self
*/
MRB_API mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self);
/*
* Join the array elements together in a string
*
* Equivalent to:
*
* ary.join(sep="")
*
* @param mrb The mruby state reference.
* @param ary The target array
* @param sep The separater, can be NULL
*/
MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep);
MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int len);
/*
* Update the capacity of the array
*
* @param mrb The mruby state reference.
* @param ary The target array.
* @param new_len The new capacity of the array
*/
MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len);
static inline mrb_int
mrb_ary_len(mrb_state *mrb, mrb_value ary)
@@ -134,6 +247,15 @@ mrb_ary_len(mrb_state *mrb, mrb_value ary)
return RARRAY_LEN(ary);
}
static inline mrb_value
ary_elt(mrb_value ary, mrb_int offset)
{
if (offset < 0 || RARRAY_LEN(ary) <= offset) {
return mrb_nil_value();
}
return RARRAY_PTR(ary)[offset];
}
MRB_END_DECL
#endif /* MRUBY_ARRAY_H */
+16 -12
View File
@@ -53,23 +53,27 @@ typedef struct mrb_value {
#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f)
#define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14)-1)
#define mrb_type(o) ((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT)
#define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT)
#define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2))
#define mrb_float(o) (o).f
#define mrb_cptr(o) mrb_ptr(o)
#define mrb_fixnum(o) (o).value.i
#define mrb_symbol(o) (o).value.sym
#ifdef MRB_64BIT
#define BOXNAN_SHIFT_LONG_POINTER(v) (((uintptr_t)(v)>>34)&0x3fff)
#else
#define BOXNAN_SHIFT_LONG_POINTER(v) 0
#endif
#define BOXNAN_SET_VALUE(o, tt, attr, v) do {\
switch (tt) {\
case MRB_TT_FALSE:\
case MRB_TT_TRUE:\
case MRB_TT_UNDEF:\
case MRB_TT_FIXNUM:\
case MRB_TT_SYMBOL: (o).attr = (v); break;\
default: (o).value.i = 0; (o).value.p = (void*)((uintptr_t)(o).value.p | (((uintptr_t)(v))>>2)); break;\
}\
(o).value.ttt = (0xfff00000|(((tt)+1)<<14));\
(o).attr = (v);\
(o).value.ttt = 0xfff00000 | (((tt)+1)<<14);\
} while (0)
#define BOXNAN_SET_OBJ_VALUE(o, tt, v) do {\
(o).value.p = (void*)((uintptr_t)(v)>>2);\
(o).value.ttt = (0xfff00000|(((tt)+1)<<14)|BOXNAN_SHIFT_LONG_POINTER(v));\
} while (0)
#define SET_FLOAT_VALUE(mrb,r,v) do { \
@@ -86,8 +90,8 @@ typedef struct mrb_value {
#define SET_BOOL_VALUE(r,b) BOXNAN_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
#define SET_INT_VALUE(r,n) BOXNAN_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
#define SET_SYM_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
#define SET_OBJ_VALUE(r,v) BOXNAN_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_VALUE(r, MRB_TT_CPTR, value.p, v)
#define SET_OBJ_VALUE(r,v) BOXNAN_SET_OBJ_VALUE(r, (((struct RObject*)(v))->tt), (v))
#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_OBJ_VALUE(r, MRB_TT_CPTR, v)
#define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
#endif /* MRUBY_BOXING_NAN_H */
+7 -3
View File
@@ -11,6 +11,10 @@
# error MRB_INT16 is too small for MRB_WORD_BOXING.
#endif
#if defined(MRB_INT64) && !defined(MRB_64BIT)
#error MRB_INT64 cannot be used with MRB_WORD_BOXING in 32-bit mode.
#endif
struct RFloat {
MRB_OBJECT_HEADER;
mrb_float f;
@@ -91,13 +95,13 @@ mrb_type(mrb_value o)
#define mrb_undef_p(o) ((o).w == MRB_Qundef)
#define mrb_nil_p(o) ((o).w == MRB_Qnil)
#define BOXWORD_SET_VALUE(o, ttt, attr, v) do {\
#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \
switch (ttt) {\
case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\
case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\
case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\
case MRB_TT_FIXNUM: (o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\
case MRB_TT_SYMBOL: (o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\
case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\
case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\
default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\
}\
} while (0)
+1
View File
@@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
}
// TODO: figure out where to put user flags
#define MRB_FLAG_IS_FROZEN (1 << 18)
#define MRB_FLAG_IS_PREPENDED (1 << 19)
#define MRB_FLAG_IS_ORIGIN (1 << 20)
#define MRB_CLASS_ORIGIN(c) do {\
+5
View File
@@ -9,8 +9,13 @@
#ifdef __cplusplus
#ifdef MRB_ENABLE_CXX_EXCEPTION
#define MRB_BEGIN_DECL
#define MRB_END_DECL
#else
# define MRB_BEGIN_DECL extern "C" {
# define MRB_END_DECL }
#endif
#else
/** Start declarations in C mode */
# define MRB_BEGIN_DECL
+2
View File
@@ -163,6 +163,7 @@ struct mrb_parser_state {
MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*);
MRB_API void mrb_parser_free(struct mrb_parser_state*);
MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*);
MRB_API double mrb_float_read(const char*, char**);
MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*);
MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
@@ -174,6 +175,7 @@ MRB_API struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*);
MRB_API struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*);
MRB_API struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,int,mrbc_context*);
MRB_API struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*);
MRB_API mrb_value mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c);
/* program load functions */
#ifndef MRB_DISABLE_STDIO
+87 -1
View File
@@ -28,40 +28,126 @@ MRB_API mrb_value mrb_hash_new_capa(mrb_state*, int);
/*
* Initializes a new hash.
*
* Equivalent to:
*
* Hash.new
*
* @param mrb The mruby state reference.
* @return The initialized hash.
*/
MRB_API mrb_value mrb_hash_new(mrb_state *mrb);
/*
* Sets a keys and values to hashes.
*
* Equivalent to:
*
* hash[key] = val
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @param key The key to set.
* @param val The value to set.
* @return The value.
*/
MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val);
/*
* Gets a value from a key.
* Gets a value from a key. If the key is not found, the default of the
* hash is used.
*
* Equivalent to:
*
* hash[key]
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @param key The key to get.
* @return The found value.
*/
MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key);
/*
* Gets a value from a key. If the key is not found, the default parameter is
* used.
*
* Equivalent to:
*
* hash.hash_key?(key) ? hash[key] : def
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @param key The key to get.
* @param def The default value.
* @return The found value.
*/
MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def);
/*
* Deletes hash key and value pair.
*
* Equivalent to:
*
* hash.delete(key)
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @param key The key to delete.
* @return The deleted value.
*/
MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key);
/*
* Gets an array of keys.
*
* Equivalent to:
*
* hash.keys
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @return An array with the keys of the hash.
*/
MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash);
MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
/*
* Check if the hash is empty
*
* Equivalent to:
*
* hash.empty?
*
* @param mrb The mruby state reference.
* @param self The target hash.
* @return True if the hash is empty, false otherwise.
*/
MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
/*
* Gets an array of values.
*
* Equivalent to:
*
* hash.values
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @return An array with the values of the hash.
*/
MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash);
/*
* Clears the hash.
*
* Equivalent to:
*
* hash.clear
*
* @param mrb The mruby state reference.
* @param hash The target hash.
* @return The hash
*/
MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
+1
View File
@@ -39,6 +39,7 @@ typedef struct mrb_irep {
struct mrb_locals *lv;
/* debug info */
mrb_bool own_filename;
const char *filename;
uint16_t *lines;
struct mrb_irep_debug_info* debug_info;
+47
View File
@@ -0,0 +1,47 @@
/*
** mruby/istruct.h - Inline structures
**
** See Copyright Notice in mruby.h
*/
#ifndef MRUBY_ISTRUCT_H
#define MRUBY_ISTRUCT_H
#include "common.h"
#include <string.h>
/**
* Inline structures that fit in RVALUE
*
* They cannot have finalizer, and cannot have instance variables.
*/
MRB_BEGIN_DECL
#define ISTRUCT_DATA_SIZE (sizeof(void*) * 3)
struct RIstruct {
MRB_OBJECT_HEADER;
char inline_data[ISTRUCT_DATA_SIZE];
};
#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj)))
#define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data)
MRB_INLINE mrb_int mrb_istruct_size()
{
return ISTRUCT_DATA_SIZE;
}
MRB_INLINE void* mrb_istruct_ptr(mrb_value object)
{
return ISTRUCT_PTR(object);
}
MRB_INLINE void mrb_istruct_copy(mrb_value dest, mrb_value src)
{
memcpy(ISTRUCT_PTR(dest), ISTRUCT_PTR(src), ISTRUCT_DATA_SIZE);
}
MRB_END_DECL
#endif /* MRUBY_ISTRUCT_H */
+4
View File
@@ -22,6 +22,10 @@ struct RBasic {
};
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v)))
#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN)
#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN)
#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN)
struct RObject {
MRB_OBJECT_HEADER;
struct iv_tbl *iv;
+3 -2
View File
@@ -25,7 +25,8 @@ struct RRange {
mrb_bool excl : 1;
};
#define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v)))
MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v);
#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v))
#define mrb_range_value(p) mrb_obj_value((void*)(p))
/*
@@ -40,7 +41,7 @@ struct RRange {
*/
MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude);
MRB_API mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len);
MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc);
mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int));
MRB_END_DECL
+2 -6
View File
@@ -7,14 +7,10 @@
#ifndef MRUBY_RE_H
#define MRUBY_RE_H
#ifdef __cplusplus
extern "C" {
#endif
MRB_BEGIN_DECL
#define REGEXP_CLASS "Regexp"
#ifdef __cplusplus
}
#endif
MRB_END_DECL
#endif /* RE_H */
+7 -12
View File
@@ -62,17 +62,13 @@ 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)
/*
* Returns a pointer from a Ruby string
*/
#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))
#define RSTRING_EMBED_LEN(s) RSTR_ENBED_LEN(RSTRING(s))
#define RSTRING_EMBED_LEN(s) RSTR_EMBED_LEN(RSTRING(s))
#define RSTRING_LEN(s) RSTR_LEN(RSTRING(s))
#define RSTRING_CAPA(s) RSTR_CAPA(RSTRING(s))
#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
@@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
#define MRB_STR_SHARED 1
#define MRB_STR_NOFREE 2
#define MRB_STR_FROZEN 4
#define MRB_STR_NO_UTF 8
#define MRB_STR_EMBED 16
#define MRB_STR_EMBED_LEN_MASK 0x3e0
@@ -110,8 +105,8 @@ MRB_API void mrb_str_modify(mrb_state*, struct RString*);
* }
*
* // Creates new Ruby strings.
* str1 = mrb_str_new_cstr(mrb, "abc");
* str2 = mrb_str_new_cstr(mrb, "def");
* str1 = mrb_str_new_lit(mrb, "abc");
* str2 = mrb_str_new_lit(mrb, "def");
*
* // Concatnates str2 to str1.
* mrb_str_concat(mrb, str1, str2);
@@ -158,8 +153,8 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value);
* }
*
* // Creates two Ruby strings from the passed in C strings.
* a = mrb_str_new_cstr(mrb, "abc");
* b = mrb_str_new_cstr(mrb, "def");
* a = mrb_str_new_lit(mrb, "abc");
* b = mrb_str_new_lit(mrb, "def");
*
* // Prints both C strings.
* mrb_p(mrb, a);
@@ -227,7 +222,7 @@ MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj);
* // handle error
* }
* // Creates a new string.
* str = mrb_str_new_cstr(mrb, "Hello, world!");
* str = mrb_str_new_lit(mrb, "Hello, world!");
* // Returns 5 characters of
* mrb_str_resize(mrb, str, 5);
* mrb_p(mrb, str);
@@ -267,7 +262,7 @@ MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len);
* // handle error
* }
* // Creates new string.
* str1 = mrb_str_new_cstr(mrb, "Hello, world!");
* str1 = mrb_str_new_lit(mrb, "Hello, world!");
* // Returns a sub-string within the range of 0..2
* str2 = mrb_str_substr(mrb, str1, 0, 2);
*
+4
View File
@@ -7,6 +7,10 @@
#ifndef MRB_THROW_H
#define MRB_THROW_H
#if defined(MRB_ENABLE_CXX_EXCEPTION) && !defined(__cplusplus)
#error Trying to use C++ exception handling in C code
#endif
#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
#define MRB_TRY(buf) do { try {
+6 -4
View File
@@ -62,12 +62,12 @@ struct mrb_state;
# define MRB_PRIx PRIx32
#endif
MRB_API double mrb_float_read(const char*, char**);
#ifdef MRB_USE_FLOAT
typedef float mrb_float;
# define str_to_mrb_float(buf) strtof(buf, NULL)
#else
typedef double mrb_float;
# define str_to_mrb_float(buf) strtod(buf, NULL)
#endif
#if defined _MSC_VER && _MSC_VER < 1900
@@ -85,7 +85,6 @@ MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...);
# define isnan _isnan
# define isinf(n) (!_finite(n) && !_isnan(n))
# define signbit(n) (_copysign(1.0, (n)) < 0.0)
# define strtof (float)strtod
static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000;
# define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE)
# define NAN ((float)(INFINITY - INFINITY))
@@ -116,7 +115,8 @@ enum mrb_vtype {
MRB_TT_ENV, /* 20 */
MRB_TT_DATA, /* 21 */
MRB_TT_FIBER, /* 22 */
MRB_TT_MAXDEFINE /* 23 */
MRB_TT_ISTRUCT, /* 23 */
MRB_TT_MAXDEFINE /* 24 */
};
#include <mruby/object.h>
@@ -210,6 +210,8 @@ mrb_obj_value(void *p)
{
mrb_value v;
SET_OBJ_VALUE(v, (struct RBasic*)p);
mrb_assert(p == mrb_ptr(v));
mrb_assert(((struct RBasic*)p)->tt == mrb_type(v));
return v;
}
+58
View File
@@ -54,9 +54,67 @@ MRB_API mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym);
MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym);
MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src);
MRB_API mrb_bool mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id);
/**
* Get a global variable. Will return nil if the var does not exist
*
* Example:
*
* !!!ruby
* # Ruby style
* var = $value
*
* !!!c
* // C style
* mrb_sym sym = mrb_intern_lit(mrb, "$value");
* mrb_value var = mrb_gv_get(mrb, sym);
*
* @param mrb The mruby state reference
* @param sym The name of the global variable
* @return The value of that global variable. May be nil
*/
MRB_API mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym);
/**
* Set a global variable
*
* Example:
*
* !!!ruby
* # Ruby style
* $value = "foo"
*
* !!!c
* // C style
* mrb_sym sym = mrb_intern_lit(mrb, "$value");
* mrb_gv_set(mrb, sym, mrb_str_new_lit("foo"));
*
* @param mrb The mruby state reference
* @param sym The name of the global variable
* @param val The value of the global variable
*/
MRB_API void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
/**
* Remove a global variable.
*
* Example:
*
* !!!ruby
* # Ruby style
* $value = nil
*
* !!!c
* // C style
* mrb_sym sym = mrb_intern_lit(mrb, "$value");
* mrb_gv_remove(mrb, sym);
*
* @param mrb The mruby state reference
* @param sym The name of the global variable
* @param val The value of the global variable
*/
MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym);
MRB_API mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym);
MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v);
MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v);
+1
View File
@@ -237,6 +237,7 @@ module MiniRake
# Time stamp for file task.
def timestamp
return Time.at(0) unless File.exist?(name)
stat = File::stat(name.to_s)
stat.directory? ? Time.at(0) : stat.mtime
end
+4 -1
View File
@@ -53,7 +53,7 @@ MRuby::GemBox.new do |conf|
# Use Enumerator class (require mruby-fiber)
conf.gem :core => "mruby-enumerator"
# Use Enumerable::Lazy class (require mruby-enumerator)
# Use Enumerator::Lazy class (require mruby-enumerator)
conf.gem :core => "mruby-enum-lazy"
# Use toplevel object (main) methods extension
@@ -71,6 +71,9 @@ MRuby::GemBox.new do |conf|
# Use Kernel module extension
conf.gem :core => "mruby-kernel-ext"
# Use class/module extension
conf.gem :core => "mruby-class-ext"
# Use mruby-compiler to build other mrbgems
conf.gem :core => "mruby-compiler"
end
+1 -1
View File
@@ -131,7 +131,7 @@ mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
if (mrb_nil_p(v)) {
mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])),
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, ary_elt(ary, i))),
mrb_fixnum_value(i)
);
}
+11
View File
@@ -301,6 +301,17 @@ assert('Array#to_h') do
assert_raise(ArgumentError) { [[1]].to_h }
end
assert('Array#to_h (Modified)') do
class A
def to_ary
$a.clear
nil
end
end
$a = [A.new]
assert_raise(TypeError) { $a.to_h }
end
assert("Array#index (block)") do
assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
@@ -43,7 +43,7 @@ check_lineno( mrb_irep_debug_info_file *info_file, uint16_t lineno )
}
static int32_t
get_break_index( mrb_debug_context *dbg, int32_t bpno )
get_break_index( mrb_debug_context *dbg, uint32_t bpno )
{
uint32_t i;
int32_t index;
@@ -296,7 +296,7 @@ mrb_debug_get_break_all( mrb_state *mrb, mrb_debug_context *dbg, uint32_t size,
int32_t
mrb_debug_get_break( mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno, mrb_debug_breakpoint *bp )
{
uint32_t index;
int32_t index;
if((mrb == NULL) || (dbg == NULL) || (bp == NULL)) {
return MRB_DEBUG_INVALID_ARGUMENT;
@@ -71,7 +71,7 @@ dirname(mrb_state *mrb, const char *path)
}
p = strrchr(path, '/');
len = p != NULL ? p - path : strlen(path);
len = p != NULL ? (size_t)(p - path) : strlen(path);
dir = mrb_malloc(mrb, len + 1);
strncpy(dir, path, len);
+14
View File
@@ -44,3 +44,17 @@ EOS
script.flush
assert_equal "\"test\"\n\"fin\"\n", `#{cmd('mruby')} #{script.path}`
end
assert('garbage collecting built-in classes') do
script = Tempfile.new('test.rb')
script.write <<RUBY
NilClass = nil
GC.start
Array.dup
print nil.class.to_s
RUBY
script.flush
assert_equal "NilClass", `#{cmd('mruby')} #{script.path}`
assert_equal 0, $?.exitstatus
end
+58 -47
View File
@@ -6,6 +6,7 @@
#include <mruby/compile.h>
#include <mruby/dump.h>
#include <mruby/variable.h>
#include <mruby/throw.h>
#ifdef MRB_DISABLE_STDIO
static void
@@ -176,6 +177,8 @@ main(int argc, char **argv)
mrbc_context *c;
mrb_value v;
mrb_sym zero_sym;
struct mrb_jmpbuf c_jmp;
int ai;
if (mrb == NULL) {
fputs("Invalid mrb_state, exiting mruby\n", stderr);
@@ -189,59 +192,67 @@ main(int argc, char **argv)
return n;
}
ARGV = mrb_ary_new_capa(mrb, args.argc);
for (i = 0; i < args.argc; i++) {
char* utf8 = mrb_utf8_from_locale(args.argv[i], -1);
if (utf8) {
mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8));
ai = mrb_gc_arena_save(mrb);
MRB_TRY(&c_jmp) {
mrb->jmp = &c_jmp;
ARGV = mrb_ary_new_capa(mrb, args.argc);
for (i = 0; i < args.argc; 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);
c = mrbc_context_new(mrb);
if (args.verbose)
c->dump_result = TRUE;
if (args.check_syntax)
c->no_exec = TRUE;
/* Set $0 */
zero_sym = mrb_intern_lit(mrb, "$0");
if (args.rfp) {
const char *cmdline;
cmdline = args.cmdline ? args.cmdline : "-";
mrbc_filename(mrb, c, cmdline);
mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline));
}
else {
mrbc_filename(mrb, c, "-e");
mrb_gv_set(mrb, zero_sym, mrb_str_new_lit(mrb, "-e"));
}
/* Load program */
if (args.mrbfile) {
v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
}
else if (args.rfp) {
v = mrb_load_file_cxt(mrb, args.rfp, c);
}
else {
char* utf8 = mrb_utf8_from_locale(args.cmdline, -1);
if (!utf8) abort();
v = mrb_load_string_cxt(mrb, utf8, c);
mrb_utf8_free(utf8);
}
}
mrb_define_global_const(mrb, "ARGV", ARGV);
c = mrbc_context_new(mrb);
if (args.verbose)
c->dump_result = TRUE;
if (args.check_syntax)
c->no_exec = TRUE;
/* Set $0 */
zero_sym = mrb_intern_lit(mrb, "$0");
if (args.rfp) {
const char *cmdline;
cmdline = args.cmdline ? args.cmdline : "-";
mrbc_filename(mrb, c, cmdline);
mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline));
}
else {
mrbc_filename(mrb, c, "-e");
mrb_gv_set(mrb, zero_sym, mrb_str_new_lit(mrb, "-e"));
}
/* Load program */
if (args.mrbfile) {
v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
}
else if (args.rfp) {
v = mrb_load_file_cxt(mrb, args.rfp, c);
}
else {
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);
if (mrb->exc) {
if (!mrb_undef_p(v)) {
mrb_print_error(mrb);
mrb_gc_arena_restore(mrb, ai);
mrbc_context_free(mrb, c);
if (mrb->exc) {
if (!mrb_undef_p(v)) {
mrb_print_error(mrb);
}
n = -1;
}
else if (args.check_syntax) {
printf("Syntax OK\n");
}
n = -1;
}
else if (args.check_syntax) {
printf("Syntax OK\n");
MRB_CATCH(&c_jmp) { /* error */
}
MRB_END_EXC(&c_jmp);
cleanup(mrb, &args);
return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+5
View File
@@ -0,0 +1,5 @@
MRuby::Gem::Specification.new('mruby-class-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'class/module extension'
end
+23
View File
@@ -0,0 +1,23 @@
#include "mruby.h"
#include "mruby/class.h"
#include "mruby/string.h"
static mrb_value
mrb_mod_name(mrb_state *mrb, mrb_value self)
{
mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self));
return mrb_nil_p(name)? name : mrb_str_dup(mrb, name);
}
void
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
{
struct RClass *mod = mrb->module_class;
mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
}
void
mrb_mruby_class_ext_gem_final(mrb_state *mrb)
{
}
+10
View File
@@ -0,0 +1,10 @@
assert 'Module#name' do
module A
class B
end
end
assert_nil A::B.singleton_class.name
assert_equal 'Fixnum', Fixnum.name
assert_equal 'A::B', A::B.name
end
+9
View File
@@ -10,3 +10,12 @@ assert('Compiling multiple files without new line in last line. #2361') do
assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp
assert_equal 0, $?.exitstatus
end
assert('parsing function with void argument') do
a, out = Tempfile.new('a.rb'), Tempfile.new('out.mrb')
a.write('f ()')
a.flush
result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} 2>&1`
assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp
assert_equal 0, $?.exitstatus
end
+92 -41
View File
@@ -93,6 +93,7 @@ codegen_error(codegen_scope *s, const char *message)
if (!s) return;
while (s->prev) {
codegen_scope *tmp = s->prev;
mrb_free(s->mrb, s->iseq);
mrb_pool_close(s->mpool);
s = tmp;
}
@@ -387,6 +388,9 @@ dispatch(codegen_scope *s, int pc)
scope_error(s);
break;
}
if (diff > MAXARG_sBx) {
codegen_error(s, "too distant jump address");
}
s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
}
@@ -500,7 +504,12 @@ new_lit(codegen_scope *s, mrb_value val)
return i;
}
static inline int
/* method symbols should be fit in 9 bits */
#define MAXMSYMLEN 512
/* maximum symbol numbers */
#define MAXSYMLEN 65536
static int
new_msym(codegen_scope *s, mrb_sym sym)
{
size_t i, len;
@@ -508,20 +517,20 @@ new_msym(codegen_scope *s, mrb_sym sym)
mrb_assert(s->irep);
len = s->irep->slen;
if (len > 256) len = 256;
if (len > MAXMSYMLEN) len = MAXMSYMLEN;
for (i=0; i<len; i++) {
if (s->irep->syms[i] == sym) return i;
if (s->irep->syms[i] == 0) break;
}
if (i == 256) {
codegen_error(s, "too many symbols (max 256)");
if (i == MAXMSYMLEN) {
codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")");
}
s->irep->syms[i] = sym;
if (i == s->irep->slen) s->irep->slen++;
return i;
}
static inline int
static int
new_sym(codegen_scope *s, mrb_sym sym)
{
size_t i;
@@ -529,13 +538,18 @@ new_sym(codegen_scope *s, mrb_sym sym)
for (i=0; i<s->irep->slen; i++) {
if (s->irep->syms[i] == sym) return i;
}
if (s->irep->slen > 125 && s->irep->slen < 256) {
s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536);
for (i = 0; i < 256 - s->irep->slen; i++) {
if (s->irep->slen == MAXSYMLEN) {
codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")");
}
if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) {
s->scapa = MAXSYMLEN;
s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN);
for (i = s->irep->slen; i < MAXMSYMLEN; i++) {
static const mrb_sym mrb_sym_zero = { 0 };
s->irep->syms[i + s->irep->slen] = mrb_sym_zero;
s->irep->syms[i] = mrb_sym_zero;
}
s->irep->slen = 256;
s->irep->slen = MAXMSYMLEN;
}
s->irep->syms[s->irep->slen] = sym;
return s->irep->slen++;
@@ -588,9 +602,6 @@ for_body(codegen_scope *s, node *tree)
push(); /* push for a block parameter */
lp = loop_push(s, LOOP_FOR);
lp->pc1 = new_label(s);
/* generate loop variable */
n2 = tree->car;
genop(s, MKOP_Ax(OP_ENTER, 0x40000));
@@ -600,6 +611,11 @@ for_body(codegen_scope *s, node *tree)
else {
gen_vmassignment(s, n2, 1, VAL);
}
/* construct loop */
lp = loop_push(s, LOOP_FOR);
lp->pc2 = new_label(s);
/* loop body */
codegen(s, tree->cdr->cdr->car, VAL);
pop();
if (s->pc > 0) {
@@ -650,6 +666,9 @@ lambda_body(codegen_scope *s, node *tree, int blk)
ka = kd = 0;
ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
codegen_error(s, "too many formal arguments");
}
a = ((mrb_aspec)(ma & 0x1f) << 18)
| ((mrb_aspec)(oa & 0x1f) << 13)
| ((ra & 1) << 12)
@@ -770,6 +789,8 @@ attrsym(codegen_scope *s, mrb_sym a)
return mrb_intern(s->mrb, name2, len+1);
}
#define CALL_MAXARGS 127
static int
gen_values(codegen_scope *s, node *t, int val)
{
@@ -778,7 +799,9 @@ gen_values(codegen_scope *s, node *t, int val)
while (t) {
is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
if (n >= 127 || is_splat) {
if (
n >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
|| is_splat) {
if (val) {
if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
codegen(s, t->car->cdr, VAL);
@@ -812,8 +835,6 @@ gen_values(codegen_scope *s, node *t, int val)
}
}
else {
codegen(s, t->car->cdr, NOVAL);
t = t->cdr;
while (t) {
codegen(s, t->car, NOVAL);
t = t->cdr;
@@ -829,8 +850,6 @@ gen_values(codegen_scope *s, node *t, int val)
return n;
}
#define CALL_MAXARGS 127
static void
gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
{
@@ -1057,7 +1076,9 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
n++;
}
}
push();
if (!val) {
push();
}
}
}
@@ -1360,6 +1381,10 @@ codegen(codegen_scope *s, node *tree, int val)
int pos1, pos2;
node *e = tree->cdr->cdr->car;
if (!tree->car) {
codegen(s, e, val);
return;
}
switch ((intptr_t)tree->car->car) {
case NODE_TRUE:
case NODE_INT:
@@ -1510,7 +1535,9 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_A(OP_LOADNIL, cursp()));
if (pos3) dispatch_linked(s, pos3);
if (head) pop();
genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
if (cursp() != pos) {
genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
}
push();
}
else {
@@ -1655,7 +1682,6 @@ codegen(codegen_scope *s, node *tree, int val)
}
tree = tree->car;
if (tree->car) { /* pre */
int first = TRUE;
t = tree->car;
n = 0;
while (t) {
@@ -1664,10 +1690,7 @@ codegen(codegen_scope *s, node *tree, int val)
n++;
}
else {
if (first) {
genop(s, MKOP_A(OP_LOADNIL, rhs+n));
first = FALSE;
}
genop(s, MKOP_A(OP_LOADNIL, rhs+n));
gen_assignment(s, t->car, rhs+n, NOVAL);
}
t = t->cdr;
@@ -1746,6 +1769,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_A(OP_RESCUE, exc));
genop(s, MKOP_A(OP_LOADF, exc));
dispatch(s, noexc);
loop_pop(s, NOVAL);
}
else if ((intptr_t)tree->car->car == NODE_CALL) {
node *n = tree->car->cdr;
@@ -1795,8 +1819,10 @@ codegen(codegen_scope *s, node *tree, int val)
int pos;
pop();
if (val && vsp >= 0) {
genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
if (val) {
if (vsp >= 0) {
genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
}
pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
}
else {
@@ -2012,7 +2038,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_REDO:
if (!s->loop) {
if (!s->loop || s->loop->type == LOOP_BEGIN || s->loop->type == LOOP_RESCUE) {
raise_error(s, "unexpected redo");
}
else {
@@ -2021,6 +2047,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
}
if (val) push();
break;
case NODE_RETRY:
@@ -2055,6 +2082,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
}
}
if (val) push();
}
break;
@@ -2194,7 +2222,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_FLOAT:
if (val) {
char *p = (char*)tree;
mrb_float f = str_to_mrb_float(p);
mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, f));
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
@@ -2208,9 +2236,9 @@ codegen(codegen_scope *s, node *tree, int val)
tree = tree->cdr;
switch (nt) {
case NODE_FLOAT:
{
if (val) {
char *p = (char*)tree;
mrb_float f = str_to_mrb_float(p);
mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, -f));
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
@@ -2219,7 +2247,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_INT:
{
if (val) {
char *p = (char*)tree->car;
int base = (intptr_t)tree->cdr->car;
mrb_int i;
@@ -2248,7 +2276,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
default:
{
if (val) {
int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
@@ -2257,6 +2285,9 @@ codegen(codegen_scope *s, node *tree, int val)
pop(); pop();
genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
}
else {
codegen(s, tree, NOVAL);
}
break;
}
}
@@ -2282,7 +2313,11 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
node *n = tree;
if (!n) break;
if (!n) {
genop(s, MKOP_A(OP_LOADNIL, cursp()));
push();
break;
}
codegen(s, n->car, VAL);
n = n->cdr;
while (n) {
@@ -2539,13 +2574,31 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_A(OP_TCLASS, cursp()));
push();
while (t) {
int symbol = new_msym(s, sym(t->car));
int symbol;
if (num >= CALL_MAXARGS - 1) {
pop_n(num);
genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num));
while (t) {
symbol = new_msym(s, sym(t->car));
push();
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
pop();
genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
t = t->cdr;
}
num = CALL_MAXARGS;
break;
}
symbol = new_msym(s, sym(t->car));
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
push();
t = t->cdr;
num++;
}
pop_n(num + 1);
pop();
if (num < CALL_MAXARGS) {
pop_n(num);
}
genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
if (val) {
push();
@@ -2713,13 +2766,13 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->icapa = 1024;
p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa);
p->irep->iseq = p->iseq;
p->irep->iseq = NULL;
p->pcapa = 32;
p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa);
p->irep->plen = 0;
p->scapa = 256;
p->scapa = MAXMSYMLEN;
p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
p->irep->slen = 0;
@@ -2797,6 +2850,7 @@ scope_finish(codegen_scope *s)
memcpy(fname, s->filename, fname_len);
fname[fname_len] = '\0';
irep->filename = fname;
irep->own_filename = TRUE;
}
irep->nlocals = s->nlocals;
@@ -2904,9 +2958,6 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
return proc;
}
MRB_CATCH(&scope->jmp) {
if (scope->filename == scope->irep->filename) {
scope->irep->filename = NULL;
}
mrb_irep_decref(mrb, scope->irep);
mrb_pool_close(scope->mpool);
return NULL;
+168 -114
View File
@@ -41,6 +41,7 @@ static void yyerror(parser_state *p, const char *s);
static void yywarn(parser_state *p, const char *s);
static void yywarning(parser_state *p, const char *s);
static void backref_error(parser_state *p, node *n);
static void void_expr_error(parser_state *p, node *n);
static void tokadd(parser_state *p, int32_t c);
#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
@@ -870,6 +871,7 @@ call_with_block(parser_state *p, node *a, node *b)
break;
case NODE_CALL:
case NODE_FCALL:
case NODE_SCALL:
n = a->cdr->cdr->cdr;
if (!n->car) n->car = cons(0, b);
else {
@@ -1097,7 +1099,7 @@ heredoc_end(parser_state *p)
%type <nd> literal numeric cpath symbol
%type <nd> top_compstmt top_stmts top_stmt
%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
%type <nd> expr_value arg_value arg_rhs primary_value
%type <nd> expr_value arg_rhs primary_value
%type <nd> if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure
%type <nd> args call_args opt_call_args
%type <nd> paren_args opt_paren_args variable
@@ -1322,7 +1324,7 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
{
$$ = new_asgn(p, $1, new_array(p, $3));
}
| mlhs '=' arg_value
| mlhs '=' arg
{
$$ = new_masgn(p, $1, $3);
}
@@ -1401,7 +1403,10 @@ expr : command_call
expr_value : expr
{
if (!$1) $$ = new_nil(p);
else $$ = $1;
else {
void_expr_error(p, $1);
$$ = $1;
}
}
;
@@ -1907,20 +1912,13 @@ arg : lhs '=' arg_rhs
}
;
arg_value : arg
{
$$ = $1;
if (!$$) $$ = new_nil(p);
}
;
aref_args : none
| args trailer
{
$$ = $1;
NODE_LINENO($$, $1);
}
| args ',' assocs trailer
| args comma assocs trailer
{
$$ = push($1, new_hash(p, $3));
}
@@ -1931,9 +1929,14 @@ aref_args : none
}
;
arg_rhs : arg %prec tOP_ASGN
arg_rhs : arg %prec tOP_ASGN
{
void_expr_error(p, $1);
$$ = $1;
}
| arg modifier_rescue arg
{
void_expr_error(p, $1);
$$ = new_mod_rescue(p, $1, $3);
}
;
@@ -1955,7 +1958,7 @@ opt_call_args : none
$$ = cons($1,0);
NODE_LINENO($$, $1);
}
| args ',' assocs ','
| args comma assocs ','
{
$$ = cons(push($1, new_hash(p, $3)), 0);
NODE_LINENO($$, $1);
@@ -1982,7 +1985,7 @@ call_args : command
$$ = cons(list1(new_hash(p, $1)), $2);
NODE_LINENO($$, $1);
}
| args ',' assocs opt_block_arg
| args comma assocs opt_block_arg
{
$$ = cons(push($1, new_hash(p, $3)), $4);
NODE_LINENO($$, $1);
@@ -2005,13 +2008,13 @@ command_args : {
}
;
block_arg : tAMPER arg_value
block_arg : tAMPER arg
{
$$ = new_block_arg(p, $2);
}
;
opt_block_arg : ',' block_arg
opt_block_arg : comma block_arg
{
$$ = $2;
}
@@ -2021,44 +2024,47 @@ opt_block_arg : ',' block_arg
}
;
args : arg_value
comma : ','
| ',' heredoc_bodies
;
args : arg
{
void_expr_error(p, $1);
$$ = cons($1, 0);
NODE_LINENO($$, $1);
}
| tSTAR arg_value
| tSTAR arg
{
void_expr_error(p, $2);
$$ = cons(new_splat(p, $2), 0);
NODE_LINENO($$, $2);
}
| args ',' arg_value
| args comma arg
{
void_expr_error(p, $3);
$$ = push($1, $3);
}
| args ',' tSTAR arg_value
| args comma tSTAR arg
{
void_expr_error(p, $4);
$$ = push($1, new_splat(p, $4));
}
| args ',' heredoc_bodies arg_value
{
$$ = push($1, $4);
}
| args ',' heredoc_bodies tSTAR arg_value
{
$$ = push($1, new_splat(p, $5));
}
;
mrhs : args ',' arg_value
mrhs : args comma arg
{
void_expr_error(p, $3);
$$ = push($1, $3);
}
| args ',' tSTAR arg_value
| args comma tSTAR arg
{
void_expr_error(p, $4);
$$ = push($1, new_splat(p, $4));
}
| tSTAR arg_value
| tSTAR arg
{
void_expr_error(p, $2);
$$ = list1(new_splat(p, $2));
}
;
@@ -2097,7 +2103,7 @@ primary : literal
}
| tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
{
$$ = 0;
$$ = new_nil(p);
}
| tLPAREN compstmt ')'
{
@@ -2125,17 +2131,9 @@ primary : literal
{
$$ = new_return(p, 0);
}
| keyword_yield '(' call_args rparen
| keyword_yield opt_paren_args
{
$$ = new_yield(p, $3);
}
| keyword_yield '(' rparen
{
$$ = new_yield(p, 0);
}
| keyword_yield
{
$$ = new_yield(p, 0);
$$ = new_yield(p, $2);
}
| keyword_not '(' expr rparen
{
@@ -2450,7 +2448,7 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
}
| f_arg ','
{
$$ = new_args(p, $1, 0, 1, 0, 0);
$$ = new_args(p, $1, 0, 0, 0, 0);
}
| f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
{
@@ -2688,7 +2686,7 @@ opt_rescue : keyword_rescue exc_list exc_var then
| none
;
exc_list : arg_value
exc_list : arg
{
$$ = list1($1);
}
@@ -2783,10 +2781,6 @@ regexp : tREGEXP_BEG tREGEXP
heredoc : tHEREDOC_BEG
;
opt_heredoc_bodies : /* none */
| heredoc_bodies
;
heredoc_bodies : heredoc_body
| heredoc_bodies heredoc_body
;
@@ -3115,7 +3109,7 @@ f_opt_asgn : tIDENTIFIER '='
}
;
f_opt : f_opt_asgn arg_value
f_opt : f_opt_asgn arg
{
$$ = cons(nsym($1), $2);
}
@@ -3233,23 +3227,23 @@ assocs : assoc
}
;
assoc : arg_value tASSOC arg_value
assoc : arg tASSOC arg
{
$$ = cons($1, $3);
}
| tLABEL arg_value
| tLABEL arg
{
$$ = cons(new_sym(p, $1), $2);
}
| tLABEL_END arg_value
| tLABEL_END arg
{
$$ = cons(new_sym(p, new_strsym(p, $1)), $2);
}
| tSTRING_BEG tLABEL_END arg_value
| tSTRING_BEG tLABEL_END arg
{
$$ = cons(new_sym(p, new_strsym(p, $2)), $3);
}
| tSTRING_BEG string_rep tLABEL_END arg_value
| tSTRING_BEG string_rep tLABEL_END arg
{
$$ = cons(new_dsym(p, push($2, $3)), $4);
}
@@ -3308,11 +3302,12 @@ rbracket : opt_nl ']'
trailer : /* none */
| nl
| ','
| comma
;
term : ';' {yyerrok;}
| nl
| heredoc_body
;
nl : '\n'
@@ -3320,10 +3315,10 @@ nl : '\n'
p->lineno++;
p->column = 0;
}
opt_heredoc_bodies
;
terms : term
| terms ';' {yyerrok;}
| terms term
;
none : /* none */
@@ -3430,6 +3425,26 @@ backref_error(parser_state *p, node *n)
}
}
static void
void_expr_error(parser_state *p, node *n)
{
int c;
if (n == NULL) return;
c = (int)(intptr_t)n->car;
switch (c) {
case NODE_BREAK:
case NODE_RETURN:
case NODE_NEXT:
case NODE_REDO:
case NODE_RETRY:
yyerror(p, "void value expression");
break;
default:
break;
}
}
static void pushback(parser_state *p, int c);
static mrb_bool peeks(parser_state *p, const char *s);
static mrb_bool skips(parser_state *p, const char *s);
@@ -3730,6 +3745,44 @@ scan_hex(const int *start, int len, int *retlen)
return retval;
}
static int32_t
read_escape_unicode(parser_state *p, int limit)
{
int32_t c;
int buf[9];
int i;
/* Look for opening brace */
i = 0;
buf[0] = nextc(p);
if (buf[0] < 0) goto eof;
if (ISXDIGIT(buf[0])) {
/* \uxxxx form */
for (i=1; i<limit; i++) {
buf[i] = nextc(p);
if (buf[i] < 0) goto eof;
if (!ISXDIGIT(buf[i])) {
pushback(p, buf[i]);
break;
}
}
}
else {
pushback(p, buf[0]);
}
c = scan_hex(buf, i, &i);
if (i == 0) {
eof:
yyerror(p, "Invalid escape character syntax");
return -1;
}
if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
yyerror(p, "Invalid Unicode code point");
return -1;
}
return c;
}
/* Return negative to indicate Unicode code point */
static int32_t
read_escape(parser_state *p)
@@ -3802,53 +3855,17 @@ read_escape(parser_state *p)
return c;
case 'u': /* Unicode */
{
int buf[9];
int i;
/* Look for opening brace */
i = 0;
buf[0] = nextc(p);
if (buf[0] < 0) goto eof;
if (buf[0] == '{') {
if (peek(p, '{')) {
/* \u{xxxxxxxx} form */
for (i=0; i<9; i++) {
buf[i] = nextc(p);
if (buf[i] < 0) goto eof;
if (buf[i] == '}') {
break;
}
else if (!ISXDIGIT(buf[i])) {
yyerror(p, "Invalid escape character syntax");
pushback(p, buf[i]);
return 0;
}
}
}
else if (ISXDIGIT(buf[0])) {
/* \uxxxx form */
for (i=1; i<4; i++) {
buf[i] = nextc(p);
if (buf[i] < 0) goto eof;
if (!ISXDIGIT(buf[i])) {
pushback(p, buf[i]);
break;
}
}
nextc(p);
c = read_escape_unicode(p, 8);
if (c < 0) return 0;
if (nextc(p) != '}') goto eof;
}
else {
pushback(p, buf[0]);
c = read_escape_unicode(p, 4);
if (c < 0) return 0;
}
c = scan_hex(buf, i, &i);
if (i == 0) {
yyerror(p, "Invalid escape character syntax");
return 0;
}
if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
yyerror(p, "Invalid Unicode code point");
return 0;
}
}
return -c;
case 'b':/* backspace */
@@ -3906,7 +3923,10 @@ parse_string(parser_state *p)
int beg = (intptr_t)p->lex_strterm->cdr->cdr->car;
int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr;
parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
int cmd_state = p->cmd_start;
if (beg == 0) beg = -3; /* should never happen */
if (end == 0) end = -3;
newtok(p);
while ((c = nextc(p)) != end || nest_level != 0) {
if (hinf && (c == '\n' || c < 0)) {
@@ -3928,7 +3948,12 @@ parse_string(parser_state *p)
}
}
if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
return tHEREDOC_END;
if (c < 0) {
p->parsing_heredoc = NULL;
}
else {
return tHEREDOC_END;
}
}
}
if (c < 0) {
@@ -3969,6 +3994,20 @@ parse_string(parser_state *p)
tokadd(p, '\\');
tokadd(p, c);
}
else if (c == 'u' && peek(p, '{')) {
/* \u{xxxx xxxx xxxx} form */
nextc(p);
while (1) {
do c = nextc(p); while (ISSPACE(c));
if (c == '}') break;
pushback(p, c);
c = read_escape_unicode(p, 8);
if (c < 0) break;
tokadd(p, -c);
}
if (hinf)
hinf->line_head = FALSE;
}
else {
pushback(p, c);
tokadd(p, read_escape(p));
@@ -4093,10 +4132,12 @@ parse_string(parser_state *p)
return tREGEXP;
}
yylval.nd = new_str(p, tok(p), toklen(p));
if (IS_LABEL_SUFFIX(0)) {
p->lstate = EXPR_BEG;
nextc(p);
return tLABEL_END;
if (IS_LABEL_POSSIBLE()) {
if (IS_LABEL_SUFFIX(0)) {
p->lstate = EXPR_BEG;
nextc(p);
return tLABEL_END;
}
}
return tSTRING;
@@ -4871,7 +4912,7 @@ parser_yylex(parser_state *p)
char *endp;
errno = 0;
d = strtod(tok(p), &endp);
d = mrb_float_read(tok(p), &endp);
if (d == 0 && endp == tok(p)) {
yywarning_s(p, "corrupted float value %s", tok(p));
}
@@ -5477,7 +5518,10 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
p->lex_strterm = NULL;
parser_init_cxt(p, c);
yyparse(p);
if (yyparse(p) != 0 || p->nerr > 0) {
p->tree = 0;
return;
}
if (!p->tree) {
p->tree = new_nil(p);
}
@@ -5657,8 +5701,8 @@ mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c)
return mrb_parse_nstring(mrb, s, strlen(s), c);
}
static mrb_value
load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
MRB_API mrb_value
mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
{
struct RClass *target = mrb->object_class;
struct RProc *proc;
@@ -5717,7 +5761,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
MRB_API mrb_value
mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c)
{
return load_exec(mrb, mrb_parse_file(mrb, f, c), c);
return mrb_load_exec(mrb, mrb_parse_file(mrb, f, c), c);
}
MRB_API mrb_value
@@ -5730,7 +5774,7 @@ mrb_load_file(mrb_state *mrb, FILE *f)
MRB_API mrb_value
mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
{
return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
}
MRB_API mrb_value
@@ -6024,7 +6068,17 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_FCALL:
case NODE_CALL:
printf("NODE_CALL:\n");
case NODE_SCALL:
switch (nodetype) {
case NODE_FCALL:
printf("NODE_FCALL:\n"); break;
case NODE_CALL:
printf("NODE_CALL(.):\n"); break;
case NODE_SCALL:
printf("NODE_SCALL(&.):\n"); break;
default:
break;
}
mrb_parser_dump(mrb, tree->car, offset+1);
dump_prefix(tree, offset+1);
printf("method='%s' (%d)\n",
@@ -6504,8 +6558,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_HEREDOC:
printf("NODE_HEREDOC:\n");
mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
printf("NODE_HEREDOC (<<%s):\n", ((parser_heredoc_info*)tree)->term);
dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break;
default:
+48 -37
View File
@@ -58,13 +58,14 @@ module Enumerable
def take(n)
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
raise ArgumentError, "attempt to take negative size" if n < 0
n = n.to_int
i = n.to_int
raise ArgumentError, "attempt to take negative size" if i < 0
ary = []
return ary if i == 0
self.each do |*val|
break if ary.size >= n
ary << val.__svalue
i -= 1
break if i == 0
end
ary
end
@@ -214,21 +215,28 @@ module Enumerable
# Returns the first element, or the first +n+ elements, of the enumerable.
# If the enumerable is empty, the first form returns <code>nil</code>, and the
# second form returns an empty array.
def first(n=NONE)
if n == NONE
def first(*args)
case args.length
when 0
self.each do |*val|
return val.__svalue
end
return nil
else
a = []
i = 0
when 1
n = args[0]
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
i = n.to_int
raise ArgumentError, "attempt to take negative size" if i < 0
ary = []
return ary if i == 0
self.each do |*val|
break if n<=i
a.push val.__svalue
i += 1
ary << val.__svalue
i -= 1
break if i == 0
end
a
ary
else
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)"
end
end
@@ -573,35 +581,38 @@ module Enumerable
# a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c.
#
def cycle(n=nil, &block)
return to_enum(:cycle, n) if !block && n.nil?
def cycle(nv = nil, &block)
return to_enum(:cycle, nv) unless block
n = nil
if nv.nil?
n = -1
else
unless nv.respond_to?(:to_int)
raise TypeError, "no implicit conversion of #{nv.class} into Integer"
end
n = nv.to_int
unless n.kind_of?(Integer)
raise TypeError, "no implicit conversion of #{nv.class} into Integer"
end
return nil if n <= 0
end
ary = []
if n.nil?
self.each do|*val|
ary.push val
block.call(*val)
end
loop do
ary.each do|e|
block.call(*e)
end
end
else
raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
each do |*i|
ary.push(i)
yield(*i)
end
return nil if ary.empty?
n = n.to_int
self.each do|*val|
ary.push val
end
count = 0
while count < n
ary.each do|e|
block.call(*e)
end
count += 1
while n < 0 || 0 < (n -= 1)
ary.each do |i|
yield(*i)
end
end
nil
end
##
+7
View File
@@ -128,6 +128,13 @@ assert("Enumerable#cycle") do
["a", "b", "c"].cycle(2) { |v| a << v }
assert_equal ["a", "b", "c", "a", "b", "c"], a
assert_raise(TypeError) { ["a", "b", "c"].cycle("a") { |v| a << v } }
empty = Class.new do
include Enumerable
def each
end
end
assert_nil empty.new.cycle { break :nope }
end
assert("Enumerable#find_index") do
+1 -1
View File
@@ -1,7 +1,7 @@
MRuby::Gem::Specification.new('mruby-enum-lazy') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Enumerable::Lazy class'
spec.summary = 'Enumerator::Lazy class'
spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator')
spec.add_dependency('mruby-enum-ext', :core => 'mruby-enum-ext')
end
+13 -2
View File
@@ -2,7 +2,7 @@ module Enumerable
# = Enumerable#lazy implementation
#
# Enumerable#lazy returns an instance of Enumerable::Lazy.
# Enumerable#lazy returns an instance of Enumerator::Lazy.
# You can use it just like as normal Enumerable object,
# except these methods act as 'lazy':
#
@@ -16,9 +16,11 @@ module Enumerable
# - flat_map collect_concat
# - zip
def lazy
Lazy.new(self)
Enumerator::Lazy.new(self)
end
end
class Enumerator
# == Acknowledgements
#
# Based on https://github.com/yhara/enumerable-lazy
@@ -40,6 +42,15 @@ module Enumerable
}
end
def to_enum(meth=:each, *args, &block)
lz = Lazy.new(self, &block)
lz.obj = self
lz.meth = meth
lz.args = args
lz
end
alias enum_for to_enum
def map(&block)
Lazy.new(self){|yielder, val|
yielder << block.call(val)
+10 -4
View File
@@ -1,9 +1,9 @@
assert("Enumerable::Lazy") do
assert("Enumerator::Lazy") do
a = [1, 2]
assert_equal Enumerable::Lazy, a.lazy.class
assert_equal Enumerator::Lazy, a.lazy.class
end
assert("Enumerable::Lazy laziness") do
assert("Enumerator::Lazy laziness") do
a = Object.new
def a.each
return to_enum :each unless block_given?
@@ -40,7 +40,13 @@ assert("Enumerable::Lazy laziness") do
assert_equal [10,20], a.b
end
assert("Enumerable::Lazy#zip with cycle") do
assert("Enumrator::Lazy#to_enum") do
lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2)
assert_kind_of Enumerator::Lazy, lazy_enum
assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4)
end
assert("Enumerator::Lazy#zip with cycle") do
e1 = [1, 2, 3].cycle
e2 = [:a, :b].cycle
assert_equal [[1,:a],[2,:b],[3,:a]], e1.lazy.zip(e2).first(3)
+11 -4
View File
@@ -153,12 +153,18 @@ class Enumerator
#
def with_index(offset=0)
return to_enum :with_index, offset unless block_given?
raise TypeError, "no implicit conversion of #{offset.class} into Integer" unless offset.respond_to?(:to_int)
offset = if offset.nil?
0
elsif offset.respond_to?(:to_int)
offset.to_int
else
raise TypeError, "no implicit conversion of #{offset.class} into Integer"
end
n = offset.to_int - 1
enumerator_block_call do |i|
n = offset - 1
enumerator_block_call do |*i|
n += 1
yield [i,n]
yield i.__svalue, n
end
end
@@ -516,6 +522,7 @@ class Enumerator
# just for internal
class Generator
include Enumerable
def initialize(&block)
raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc
@@ -50,6 +50,9 @@ end
assert 'Enumerator#with_index' do
assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a)
assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a)
a = []
@obj.to_enum(:foo, 1, 2, 3).with_index(10).with_index(20) { |*i| a << i }
assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a
end
assert 'Enumerator#with_index nonnum offset' do
+7 -10
View File
@@ -5,6 +5,9 @@
#include <mruby/proc.h>
#include <mruby/opcode.h>
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
static struct mrb_irep *
get_closure_irep(mrb_state *mrb, int level)
{
@@ -209,22 +212,15 @@ f_eval(mrb_state *mrb, mrb_value self)
mrb_value binding = mrb_nil_value();
char *file = NULL;
mrb_int line = 1;
mrb_value ret;
struct RProc *proc;
mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
proc = create_proc_from_string(mrb, s, len, binding, file, line);
ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
if (mrb->exc) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
}
return ret;
mrb_assert(!MRB_PROC_CFUNC_P(proc));
return mrb_exec_irep(mrb, self, proc);
}
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
#define CI_ACC_SKIP -1
static mrb_value
@@ -250,7 +246,8 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
c->ci->target_class = mrb_class_ptr(cv);
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
mrb->c->ci->env = NULL;
return mrb_vm_run(mrb, proc, mrb->c->stack[0], 0);
mrb_assert(!MRB_PROC_CFUNC_P(proc));
return mrb_exec_irep(mrb, self, proc);
}
else {
mrb_get_args(mrb, "&", &b);
+5
View File
@@ -0,0 +1,5 @@
MRuby::Gem::Specification.new('mruby-inline-struct') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'inline structure'
end
+83
View File
@@ -0,0 +1,83 @@
#include <mruby.h>
#include <mruby/class.h>
#include <mruby/string.h>
#include <mruby/istruct.h>
static mrb_value
istruct_test_initialize(mrb_state *mrb, mrb_value self)
{
char *string = (char*)mrb_istruct_ptr(self);
mrb_int size = mrb_istruct_size();
mrb_value object;
mrb_get_args(mrb, "o", &object);
if (mrb_float_p(object))
{
snprintf(string, size, "float(%.3f)", mrb_float(object));
}
else if (mrb_fixnum_p(object))
{
snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object));
}
else if (mrb_string_p(object))
{
snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object));
}
string[size - 1] = 0; // force NULL at the end
return self;
}
static mrb_value
istruct_test_to_s(mrb_state *mrb, mrb_value self)
{
return mrb_str_new_cstr(mrb, (const char*)mrb_istruct_ptr(self));
}
static mrb_value
istruct_test_length(mrb_state *mrb, mrb_value self)
{
return mrb_fixnum_value(mrb_istruct_size());
}
static mrb_value
istruct_test_test_receive(mrb_state *mrb, mrb_value self)
{
mrb_value object;
mrb_get_args(mrb, "o", &object);
if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest"))
{
mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest");
}
return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's');
}
static mrb_value
istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self)
{
char *ptr;
mrb_get_args(mrb, "I", &ptr);
return mrb_bool_value(ptr[0] == 's');
}
static mrb_value
istruct_test_mutate(mrb_state *mrb, mrb_value self)
{
char *ptr = (char*)mrb_istruct_ptr(self);
memcpy(ptr, "mutate", 6);
return mrb_nil_value();
}
void mrb_mruby_inline_struct_gem_test(mrb_state *mrb)
{
struct RClass *cls;
cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class);
MRB_SET_INSTANCE_TT(cls, MRB_TT_ISTRUCT);
mrb_define_method(mrb, cls, "initialize", istruct_test_initialize, MRB_ARGS_REQ(1));
mrb_define_method(mrb, cls, "to_s", istruct_test_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, cls, "mutate", istruct_test_mutate, MRB_ARGS_NONE());
mrb_define_class_method(mrb, cls, "length", istruct_test_length, MRB_ARGS_NONE());
mrb_define_class_method(mrb, cls, "test_receive", istruct_test_test_receive, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, cls, "test_receive_direct", istruct_test_test_receive_direct, MRB_ARGS_REQ(1));
}
+151
View File
@@ -0,0 +1,151 @@
##
# InlineStruct Test
class InlineStructTest
def extra_method
:ok
end
def test_ivar_set
@var = :ivar
end
def test_ivar_get
@vat
end
end
assert('InlineStructTest#dup') do
obj = InlineStructTest.new(1)
assert_equal obj.to_s, 'fixnum(1)'
assert_equal obj.dup.to_s, 'fixnum(1)'
end
assert('InlineStructTest#clone') do
obj = InlineStructTest.new(1)
assert_equal obj.to_s, 'fixnum(1)'
assert_equal obj.clone.to_s, 'fixnum(1)'
end
assert('InlineStruct#object_id') do
obj1 = InlineStructTest.new(1)
obj2 = InlineStructTest.new(1)
assert_not_equal obj1, obj2
assert_not_equal obj1.object_id, obj2.object_id
assert_not_equal obj1.object_id, obj1.dup.object_id
assert_not_equal obj1.object_id, obj1.clone.object_id
end
assert('InlineStructTest#mutate (dup)') do
obj1 = InlineStructTest.new("foo")
assert_equal obj1.to_s, "string(foo)"
obj2 = obj1.dup
assert_equal obj2.to_s, "string(foo)"
obj1.mutate
assert_equal obj1.to_s, "mutate(foo)"
assert_equal obj2.to_s, "string(foo)"
end
assert('InlineStructTest#mutate (clone)') do
obj1 = InlineStructTest.new("foo")
assert_equal obj1.to_s, "string(foo)"
obj2 = obj1.clone
assert_equal obj2.to_s, "string(foo)"
obj1.mutate
assert_equal obj1.to_s, "mutate(foo)"
assert_equal obj2.to_s, "string(foo)"
end
assert('InlineStructTest#test_receive(string)') do
assert_equal InlineStructTest.test_receive(InlineStructTest.new('a')), true
end
assert('InlineStructTest#test_receive(float)') do
assert_equal InlineStructTest.test_receive(InlineStructTest.new(1.25)), false
end
assert('InlineStructTest#test_receive(invalid object)') do
assert_raise(TypeError) do
InlineStructTest.test_receive([])
end
end
assert('InlineStructTest#test_receive(string)') do
assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new('a')), true
end
assert('InlineStructTest#test_receive(float)') do
assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new(1.25)), false
end
assert('InlineStructTest#test_receive(invalid object)') do
assert_raise(TypeError) do
InlineStructTest.test_receive_direct([])
end
end
assert('InlineStructTest#extra_method') do
assert_equal InlineStructTest.new(1).extra_method, :ok
end
assert('InlineStructTest instance variable') do
obj = InlineStructTest.new(1)
assert_raise(ArgumentError) do
obj.test_ivar_set
end
assert_equal obj.test_ivar_get, nil
end
# 64-bit mode
if InlineStructTest.length == 24
assert('InlineStructTest length [64 bit]') do
assert_equal InlineStructTest.length, 3 * 8
end
assert('InlineStructTest w/float [64 bit]') do
obj = InlineStructTest.new(1.25)
assert_equal obj.to_s, "float(1.250)"
end
assert('InlineStructTest w/fixnum [64 bit]') do
obj = InlineStructTest.new(42)
assert_equal obj.to_s, "fixnum(42)"
end
assert('InlineStructTest w/string [64 bit]') do
obj = InlineStructTest.new("hello")
assert_equal obj.to_s, "string(hello)"
end
assert('InlineStructTest w/long string [64 bit]') do
obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure")
assert_equal obj.to_s, "string(this won't fit i"
end
end
# 32-bit mode
if InlineStructTest.length == 12
assert('InlineStructTest length [32 bit]') do
assert_equal InlineStructTest.length, 3 * 4
end
assert('InlineStructTest w/float [32 bit]') do
obj = InlineStructTest.new(1.25)
assert_equal obj.to_s, "float(1.250"
end
assert('InlineStructTest w/fixnum [32 bit]') do
obj = InlineStructTest.new(42)
assert_equal obj.to_s, "fixnum(42)"
end
assert('InlineStructTest w/string [32 bit]') do
obj = InlineStructTest.new("hello")
assert_equal obj.to_s, "string(hell"
end
assert('InlineStructTest w/long string [32 bit]') do
obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure")
assert_equal obj.to_s, "string(this"
end
end
+59
View File
@@ -2,6 +2,64 @@
#include <mruby/error.h>
#include <mruby/array.h>
#include <mruby/hash.h>
#include <mruby/range.h>
static mrb_value
mrb_f_caller(mrb_state *mrb, mrb_value self)
{
mrb_value bt, v, length;
mrb_int bt_len, argc, lev, n;
bt = mrb_get_backtrace(mrb);
bt_len = RARRAY_LEN(bt);
argc = mrb_get_args(mrb, "|oo", &v, &length);
switch (argc) {
case 0:
lev = 1;
n = bt_len - lev;
break;
case 1:
if (mrb_type(v) == MRB_TT_RANGE) {
mrb_int beg, len;
if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) {
lev = beg;
n = len;
}
else {
return mrb_nil_value();
}
}
else {
v = mrb_to_int(mrb, v);
lev = mrb_fixnum(v);
if (lev < 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
}
n = bt_len - lev;
}
break;
case 2:
lev = mrb_fixnum(mrb_to_int(mrb, v));
n = mrb_fixnum(mrb_to_int(mrb, length));
if (lev < 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
}
if (n < 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%S)", length);
}
break;
default:
lev = n = 0;
break;
}
if (n == 0) {
return mrb_ary_new(mrb);
}
return mrb_funcall(mrb, bt, "[]", 2, mrb_fixnum_value(lev), mrb_fixnum_value(n));
}
/*
* call-seq:
@@ -170,6 +228,7 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb)
struct RClass *krn = mrb->kernel_module;
mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2));
mrb_define_module_function(mrb, krn, "caller", mrb_f_caller, MRB_ARGS_OPT(2));
mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY());
mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1));
+29
View File
@@ -3,6 +3,35 @@ assert('Kernel.fail, Kernel#fail') do
assert_raise(RuntimeError) { Kernel.fail }
end
assert('Kernel.caller, Kernel#caller') do
skip "backtrace isn't available" if caller(0).empty?
c = Class.new do
def foo(*args)
caller(*args)
end
def bar(*args)
foo(*args)
end
def baz(*args)
bar(*args)
end
end
assert_equal "#bar", c.new.baz[0][-4..-1]
assert_equal "#foo", c.new.baz(0)[0][-4..-1]
assert_equal "#bar", c.new.baz(1)[0][-4..-1]
assert_equal "#baz", c.new.baz(2)[0][-4..-1]
assert_equal ["#foo", "#bar"], c.new.baz(0, 2).map { |i| i[-4..-1] }
assert_equal ["#bar", "#baz"], c.new.baz(1..2).map { |i| i[-4..-1] }
assert_nil c.new.baz(10..20)
assert_raise(ArgumentError) { c.new.baz(-1) }
assert_raise(ArgumentError) { c.new.baz(-1, 1) }
assert_raise(ArgumentError) { c.new.baz(1, -1) }
assert_raise(TypeError) { c.new.baz(nil) }
end
assert('Kernel#__method__') do
assert_equal(:m, Class.new {def m; __method__; end}.new.m)
assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m)
+1 -1
View File
@@ -96,7 +96,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE());
mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE());
mrb_define_method(mrb, mrb->object_class, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
}
void
+28
View File
@@ -23,3 +23,31 @@ assert('Object#tap') do
], ret
assert_equal(:tap_ok, Class.new {def m; tap{return :tap_ok}; end}.new.m)
end
assert('instance_exec on primitives with class and module definition') do
begin
class A
1.instance_exec do
class B
end
end
end
assert_kind_of Class, A::B
ensure
Object.remove_const :A
end
begin
class A
1.instance_exec do
module B
end
end
end
assert_kind_of Module, A::B
ensure
Object.remove_const :A
end
end
@@ -49,7 +49,7 @@ static mrb_value
os_count_objects(mrb_state *mrb, mrb_value self)
{
struct os_count_struct obj_count = { 0 };
enum mrb_vtype i;
mrb_int i;
mrb_value hash;
if (mrb_get_args(mrb, "|H", &hash) == 0) {
+1 -1
View File
@@ -22,7 +22,7 @@ printstr(mrb_state *mrb, mrb_value obj)
int mlen = RSTRING_LEN(obj);
char* utf8 = RSTRING_PTR(obj);
int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0);
wchar_t* utf16 = mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t));
wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t));
if (utf16 == NULL) return;
if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) {
utf16[wlen] = 0;
+3
View File
@@ -114,6 +114,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
// TODO cfunc aspec is not implemented yet
return mrb_ary_new(mrb);
}
if (!irep) {
return mrb_ary_new(mrb);
}
if (!irep->lv) {
return mrb_ary_new(mrb);
}
+4 -2
View File
@@ -124,6 +124,8 @@ mrb_random_init(mrb_state *mrb, mrb_value self)
mrb_value seed;
mt_state *t;
seed = get_opt(mrb);
/* avoid memory leaks */
t = (mt_state*)DATA_PTR(self);
if (t) {
@@ -134,7 +136,6 @@ mrb_random_init(mrb_state *mrb, mrb_value self)
t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state));
t->mti = N + 1;
seed = get_opt(mrb);
seed = mrb_random_mt_srand(mrb, t, seed);
if (mrb_nil_p(seed)) {
t->has_seed = FALSE;
@@ -266,7 +267,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary)
mrb_int n = 0;
mrb_bool given;
mt_state *random = NULL;
mrb_int len = RARRAY_LEN(ary);
mrb_int len;
mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type);
if (random == NULL) {
@@ -274,6 +275,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary)
}
mrb_random_rand_seed(mrb, random);
mt_rand(random);
len = RARRAY_LEN(ary);
if (!given) { /* pick one element */
switch (len) {
case 0:
+12
View File
@@ -74,3 +74,15 @@ assert('Array#shuffle!(random)') do
ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
end
assert('Array#sample checks input length after reading arguments') do
$ary = [1, 2, 3]
class ArrayChange
def to_i
$ary << 4
4
end
end
assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort
end
+31
View File
@@ -0,0 +1,31 @@
class Range
##
# call-seq:
# rng.first -> obj
# rng.first(n) -> an_array
#
# Returns the first object in the range, or an array of the first +n+
# elements.
#
# (10..20).first #=> 10
# (10..20).first(3) #=> [10, 11, 12]
#
def first(*args)
return self.begin if args.empty?
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1
nv = args[0]
raise TypeError, "no implicit conversion from nil to integer" if nv.nil?
raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int)
n = nv.to_int
raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer)
raise ArgumentError, "negative array size (or size too big)" unless 0 <= n
ary = []
each do |i|
break if n <= 0
ary.push(i)
n -= 1
end
ary
end
end
+25 -39
View File
@@ -1,6 +1,7 @@
#include <mruby.h>
#include <mruby/range.h>
#include <math.h>
#include <float.h>
static mrb_bool
r_le(mrb_state *mrb, mrb_value a, mrb_value b)
@@ -43,7 +44,7 @@ static mrb_value
mrb_range_cover(mrb_state *mrb, mrb_value range)
{
mrb_value val;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
mrb_get_args(mrb, "o", &val);
@@ -65,32 +66,6 @@ mrb_range_cover(mrb_state *mrb, mrb_value range)
return mrb_false_value();
}
/*
* call-seq:
* rng.first -> obj
* rng.first(n) -> an_array
*
* Returns the first object in the range, or an array of the first +n+
* elements.
*
* (10..20).first #=> 10
* (10..20).first(3) #=> [10, 11, 12]
*/
static mrb_value
mrb_range_first(mrb_state *mrb, mrb_value range)
{
mrb_int num;
mrb_value array;
struct RRange *r = mrb_range_ptr(range);
if (mrb_get_args(mrb, "|i", &num) == 0) {
return r->edges->beg;
}
array = mrb_funcall(mrb, range, "to_a", 0);
return mrb_funcall(mrb, array, "first", 1, mrb_fixnum_value(num));
}
/*
* call-seq:
* rng.last -> obj
@@ -112,7 +87,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
{
mrb_value num;
mrb_value array;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
if (mrb_get_args(mrb, "|o", &num) == 0) {
return r->edges->end;
@@ -136,15 +111,17 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
static mrb_value
mrb_range_size(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
double beg_f, end_f;
mrb_float beg_f, end_f;
mrb_bool num_p = TRUE;
mrb_bool excl;
beg = r->edges->beg;
end = r->edges->end;
excl = r->excl;
if (mrb_fixnum_p(beg)) {
beg_f = (double)mrb_fixnum(beg);
beg_f = (mrb_float)mrb_fixnum(beg);
}
else if (mrb_float_p(beg)) {
beg_f = mrb_float(beg);
@@ -153,7 +130,7 @@ mrb_range_size(mrb_state *mrb, mrb_value range)
num_p = FALSE;
}
if (mrb_fixnum_p(end)) {
end_f = (double)mrb_fixnum(end);
end_f = (mrb_float)mrb_fixnum(end);
}
else if (mrb_float_p(end)) {
end_f = mrb_float(end);
@@ -162,14 +139,24 @@ mrb_range_size(mrb_state *mrb, mrb_value range)
num_p = FALSE;
}
if (num_p) {
double f;
mrb_float n = end_f - beg_f;
mrb_float err = (fabs(beg_f) + fabs(end_f) + fabs(end_f-beg_f)) * MRB_FLOAT_EPSILON;
if (beg_f > end_f) return mrb_fixnum_value(0);
f = end_f - beg_f;
if (!r->excl) {
return mrb_fixnum_value((mrb_int)ceil(f + 1));
if (err>0.5) err=0.5;
if (excl) {
if (n<=0) return mrb_fixnum_value(0);
if (n<1)
n = 0;
else
n = floor(n - err);
}
return mrb_fixnum_value((mrb_int)ceil(f));
else {
if (n<0) return mrb_fixnum_value(0);
n = floor(n + err);
}
if (isinf(n+1))
return mrb_float_value(mrb, INFINITY);
return mrb_fixnum_value((mrb_int)n+1);
}
return mrb_nil_value();
}
@@ -180,7 +167,6 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb)
struct RClass * s = mrb_class_get(mrb, "Range");
mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "first", mrb_range_first, MRB_ARGS_OPT(1));
mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1));
mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE());
}
+3
View File
@@ -10,6 +10,7 @@ end
assert('Range#first') do
assert_equal 10, (10..20).first
assert_equal [10, 11, 12], (10..20).first(3)
assert_equal [0, 1, 2], (0..Float::INFINITY).first(3)
end
assert('Range#last') do
@@ -25,5 +26,7 @@ assert('Range#size') do
assert_equal 6, (1...6.3).size
assert_equal 5, (1...6.0).size
assert_equal 5, (1.1...6).size
assert_equal 15, (1.0..15.9).size
assert_equal Float::INFINITY, (0..Float::INFINITY).size
assert_nil ('a'..'z').size
end
+64 -28
View File
@@ -116,8 +116,9 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
#define CHECK(l) do {\
/* int cr = ENC_CODERANGE(result);*/\
while (blen + (l) >= bsiz) {\
while ((l) >= bsiz - blen) {\
bsiz*=2;\
if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \
}\
mrb_str_resize(mrb, result, bsiz);\
/* ENC_CODERANGE_SET(result, cr);*/\
@@ -136,29 +137,63 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
blen += (l);\
} while (0)
#define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : \
posarg == -1 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
posarg == -2 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
static void
check_next_arg(mrb_state *mrb, int posarg, int nextarg)
{
switch (posarg) {
case -1:
mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg));
break;
case -2:
mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg));
break;
default:
break;
}
}
static void
check_pos_arg(mrb_state *mrb, int posarg, int n)
{
if (posarg > 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)",
mrb_fixnum_value(n), mrb_fixnum_value(posarg));
}
if (posarg == -2) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n));
}
if (n < 1) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n));
}
}
static void
check_name_arg(mrb_state *mrb, int posarg, const char *name, int len)
{
if (posarg > 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)",
mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg));
}
if (posarg == -1) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len)));
}
}
#define GETNEXTARG() (\
check_next_arg(mrb, posarg, nextarg),\
(posarg = nextarg++, GETNTHARG(posarg)))
#define GETPOSARG(n) (posarg > 0 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", mrb_fixnum_value(n), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
posarg == -2 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n)), mrb_undef_value()) : \
((n < 1) ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n)), mrb_undef_value()) : \
(posarg = -1, GETNTHARG(n))))
#define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : GETNEXTARG())
#define GETPOSARG(n) (\
check_pos_arg(mrb, posarg, n),\
(posarg = -1, GETNTHARG(n)))
#define GETNTHARG(nth) \
((nth >= argc) ? (mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"), mrb_undef_value()) : argv[nth])
#define GETNAMEARG(id, name, len) ( \
posarg > 0 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)", mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
posarg == -1 ? \
(mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len))), mrb_undef_value()) : \
#define GETNAMEARG(id, name, len) (\
check_name_arg(mrb, posarg, name, len),\
(posarg = -2, mrb_hash_fetch(mrb, get_hash(mrb, &hash, argc, argv), id, mrb_undef_value())))
#define GETNUM(n, val) \
@@ -182,7 +217,7 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
tmp_v = GETPOSARG(n); \
} \
else { \
tmp_v = GETARG(); \
tmp_v = GETNEXTARG(); \
p = t; \
} \
num = mrb_fixnum(tmp_v); \
@@ -675,6 +710,7 @@ retry:
else {
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
}
mrb_check_type(mrb, tmp, MRB_TT_STRING);
c = RSTRING_PTR(tmp);
n = RSTRING_LEN(tmp);
if (!(flags & FWIDTH)) {
@@ -686,10 +722,10 @@ retry:
CHECK(n);
memcpy(buf+blen, c, n);
blen += n;
FILL(' ', width-1);
if (width>0) FILL(' ', width-1);
}
else {
FILL(' ', width-1);
if (width>0) FILL(' ', width-1);
CHECK(n);
memcpy(buf+blen, c, n);
blen += n;
@@ -843,20 +879,20 @@ retry:
strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf));
break;
case 8:
snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIo, v);
snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIo, v);
break;
case 10:
snprintf(nbuf, sizeof(nbuf), "%"MRB_PRId, v);
snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
break;
case 16:
snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIx, v);
snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIx, v);
break;
}
s = nbuf;
}
else {
s = nbuf;
if (v < 0) {
if (base != 10 && v < 0) {
dots = 1;
}
switch (base) {
@@ -864,13 +900,13 @@ retry:
strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1);
break;
case 8:
snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIo, v);
snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v);
break;
case 10:
snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRId, v);
snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRId, v);
break;
case 16:
snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIx, v);
snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v);
break;
}
if (v < 0) {
+24 -1
View File
@@ -5,5 +5,28 @@ assert('String#%') do
assert_equal "one=1", "one=%d" % 1
assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ]
assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" }
assert_equal 16, ("%b" % (1<<15)).size
assert_equal 15, ("%b" % (1<<14)).size
end
assert("String#% with invalid chr") do
begin
class Fixnum
alias_method :chr_, :chr if method_defined?(:chr)
def chr
nil
end
end
assert_raise TypeError do
"%c" % 0
end
ensure
class Fixnum
if method_defined?(:chr_)
alias_method :chr, :chr_
remove_method :chr_
end
end
end
end
+28 -22
View File
@@ -45,7 +45,7 @@ class String
def lstrip
a = 0
z = self.size - 1
a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z
a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
(z >= 0) ? self[a..z] : ""
end
@@ -62,7 +62,7 @@ class String
def rstrip
a = 0
z = self.size - 1
z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z
z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
(z >= 0) ? self[a..z] : ""
end
@@ -78,8 +78,8 @@ class String
def strip
a = 0
z = self.size - 1
a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z
z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z
a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
(z >= 0) ? self[a..z] : ""
end
@@ -275,15 +275,11 @@ class String
# "hello".ljust(20) #=> "hello "
# "hello".ljust(20, '1234') #=> "hello123412341234123"
def ljust(idx, padstr = ' ')
if idx <= self.size
return self
end
newstr = self.dup
newstr << padstr
while newstr.size <= idx
newstr << padstr
end
return newstr.slice(0,idx)
raise ArgumentError, 'zero width padding' if padstr == ''
return self if idx <= self.size
pad_repetitions = (idx / padstr.length).ceil
padding = (padstr * pad_repetitions)[0...(idx - self.length)]
self + padding
end
##
@@ -298,15 +294,11 @@ class String
# "hello".rjust(20) #=> " hello"
# "hello".rjust(20, '1234') #=> "123412341234123hello"
def rjust(idx, padstr = ' ')
if idx <= self.size
return self
end
padsize = idx - self.size
newstr = padstr.dup
while newstr.size <= padsize
newstr << padstr
end
return newstr.slice(0,padsize) + self
raise ArgumentError, 'zero width padding' if padstr == ''
return self if idx <= self.size
pad_repetitions = (idx / padstr.length).ceil
padding = (padstr * pad_repetitions)[0...(idx - self.length)]
padding + self
end
# str.upto(other_str, exclusive=false) {|s| block } -> str
@@ -385,4 +377,18 @@ class String
end
end
alias each_codepoint codepoints
##
# call-seq:
# str.prepend(other_str) -> str
#
# Prepend---Prepend the given string to <i>str</i>.
#
# a = "world"
# a.prepend("hello ") #=> "hello world"
# a #=> "hello world"
def prepend(arg)
self[0, 0] = arg
self
end
end
+20 -45
View File
@@ -23,10 +23,11 @@ static mrb_value
mrb_str_setbyte(mrb_state *mrb, mrb_value str)
{
mrb_int pos, byte;
long len = RSTRING_LEN(str);
long len;
mrb_get_args(mrb, "ii", &pos, &byte);
len = RSTRING_LEN(str);
if (pos < -len || len <= pos)
mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos));
if (pos < 0)
@@ -55,8 +56,14 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str)
mrb_int beg;
len = RSTRING_LEN(str);
if (mrb_range_beg_len(mrb, a1, &beg, &len, len)) {
switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) {
case 0: /* not range */
break;
case 1: /* range */
return mrb_str_substr(mrb, str, beg, len);
case 2: /* out of range */
mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1);
break;
}
return mrb_nil_value();
}
@@ -307,13 +314,14 @@ mrb_str_lines(mrb_state *mrb, mrb_value self)
int ai;
mrb_int len;
mrb_value arg;
char *p = RSTRING_PTR(self), *t;
char *e = p + RSTRING_LEN(self);
char *b = RSTRING_PTR(self);
char *p = b, *t;
char *e = b + RSTRING_LEN(self);
mrb_get_args(mrb, "&", &blk);
result = mrb_ary_new(mrb);
ai = mrb_gc_arena_save(mrb);
if (!mrb_nil_p(blk)) {
while (p < e) {
t = p;
@@ -322,11 +330,17 @@ mrb_str_lines(mrb_state *mrb, mrb_value self)
len = (mrb_int) (p - t);
arg = mrb_str_new(mrb, t, len);
mrb_yield_argv(mrb, blk, 1, &arg);
mrb_gc_arena_restore(mrb, ai);
if (b != RSTRING_PTR(self)) {
ptrdiff_t diff = p - b;
b = RSTRING_PTR(self);
p = b + diff;
}
e = b + RSTRING_LEN(self);
}
return self;
}
while (p < e) {
ai = mrb_gc_arena_save(mrb);
t = p;
while (p < e && *p != '\n') p++;
if (*p == '\n') p++;
@@ -429,44 +443,6 @@ mrb_str_succ(mrb_state *mrb, mrb_value self)
return str;
}
/*
* call-seq:
* str.prepend(other_str) -> str
*
* Prepend---Prepend the given string to <i>str</i>.
*
* a = "world"
* a.prepend("hello ") #=> "hello world"
* a #=> "hello world"
*/
static mrb_value
mrb_str_prepend(mrb_state *mrb, mrb_value self)
{
struct RString *s1 = mrb_str_ptr(self), *s2, *temp_s;
mrb_int len;
mrb_value other, temp_str;
mrb_get_args(mrb, "S", &other);
mrb_str_modify(mrb, s1);
if (!mrb_string_p(other)) {
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
len = RSTR_LEN(s1) + RSTR_LEN(s2);
temp_str = mrb_str_new(mrb, NULL, RSTR_LEN(s1));
temp_s = mrb_str_ptr(temp_str);
memcpy(RSTR_PTR(temp_s), RSTR_PTR(s1), RSTR_LEN(s1));
if (RSTRING_CAPA(self) < len) {
mrb_str_resize(mrb, self, len);
}
memcpy(RSTR_PTR(s1), RSTR_PTR(s2), RSTR_LEN(s2));
memcpy(RSTR_PTR(s1) + RSTR_LEN(s2), RSTR_PTR(temp_s), RSTR_LEN(temp_s));
RSTR_SET_LEN(s1, len);
RSTR_PTR(s1)[len] = '\0';
return self;
}
#ifdef MRB_UTF8_STRING
static const char utf8len_codepage_zero[256] =
{
@@ -554,7 +530,6 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "prepend", mrb_str_prepend, MRB_ARGS_REQ(1));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
+58
View File
@@ -30,6 +30,18 @@ assert('String#setbyte') do
assert_equal("Hello", str1)
end
assert("String#setbyte raises IndexError if arg conversion resizes String") do
$s = "01234\n"
class Tmp
def to_i
$s.chomp! ''
95
end
end
tmp = Tmp.new
assert_raise(IndexError) { $s.setbyte(5, tmp) }
end
assert('String#byteslice') do
str1 = "hello"
assert_equal("e", str1.byteslice(1))
@@ -421,6 +433,7 @@ end
assert('String#ljust') do
assert_equal "hello", "hello".ljust(4)
assert_equal "hello ", "hello".ljust(20)
assert_equal 20, "hello".ljust(20).length
assert_equal "hello123412341234123", "hello".ljust(20, '1234')
assert_equal "hello", "hello".ljust(-3)
end
@@ -428,10 +441,55 @@ end
assert('String#rjust') do
assert_equal "hello", "hello".rjust(4)
assert_equal " hello", "hello".rjust(20)
assert_equal 20, "hello".rjust(20).length
assert_equal "123412341234123hello", "hello".rjust(20, '1234')
assert_equal "hello", "hello".rjust(-3)
end
if UTF8STRING
assert('String#ljust with UTF8') do
assert_equal "helloん ", "helloん".ljust(20)
assert_equal "helloó ", "helloó".ljust(34)
assert_equal 34, "helloó".ljust(34).length
assert_equal "helloんんんんんんんんんんんんんん", "hello".ljust(19, 'ん')
assert_equal "helloんんんんんんんんんんんんんんん", "hello".ljust(20, 'ん')
end
assert('String#rjust with UTF8') do
assert_equal " helloん", "helloん".rjust(20)
assert_equal " helloó", "helloó".rjust(34)
# assert_equal 34, "helloó".rjust(34).length
assert_equal "んんんんんんんんんんんんんんhello", "hello".rjust(19, 'ん')
assert_equal "んんんんんんんんんんんんんんんhello", "hello".rjust(20, 'ん')
end
assert('UTF8 byte counting') do
ret = ' '
ret[-6..-1] = "helloó"
assert_equal 34, ret.length
end
end
assert('String#ljust should not change string') do
a = "hello"
a.ljust(20)
assert_equal "hello", a
end
assert('String#rjust should not change string') do
a = "hello"
a.rjust(20)
assert_equal "hello", a
end
assert('String#ljust should raise on zero width padding') do
assert_raise(ArgumentError) { "foo".ljust(10, '') }
end
assert('String#rjust should raise on zero width padding') do
assert_raise(ArgumentError) { "foo".rjust(10, '') }
end
assert('String#upto') do
a = "aa"
start = "aa"
+11 -21
View File
@@ -203,7 +203,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
}
if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) {
mrb_warn(mrb, "redefining constant Struct::%S", name);
/* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */
mrb_const_remove(mrb, mrb_obj_value(klass), id);
}
c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass);
}
@@ -273,31 +273,21 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
}
else {
if (argc > 0) name = argv[0];
if (argc > 1) rest = argv[1];
if (mrb_array_p(rest)) {
if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
/* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
mrb_ary_unshift(mrb, rest, name);
name = mrb_nil_value();
}
}
else {
pargv = &argv[1];
argcnt = argc-1;
if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
/* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
name = mrb_nil_value();
pargv = &argv[0];
argcnt++;
}
rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
pargv = &argv[1];
argcnt = argc-1;
if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
/* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
name = mrb_nil_value();
pargv = &argv[0];
argcnt++;
}
rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
for (i=0; i<RARRAY_LEN(rest); i++) {
id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]);
mrb_ary_set(mrb, rest, i, mrb_symbol_value(id));
}
}
st = make_struct(mrb, name, rest, struct_class(mrb));
st = make_struct(mrb, name, rest, mrb_class_ptr(klass));
if (!mrb_nil_p(b)) {
mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st));
}
@@ -703,7 +693,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb)
mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_ANY());
}
void
+39
View File
@@ -158,3 +158,42 @@ assert("Struct#dig") do
assert_equal 1, a.dig(:purple, :red)
assert_equal 1, a.dig(1, 0)
end
assert("Struct.new removes existing constant") do
skip "redefining Struct with same name cause warnings"
begin
assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
ensure
Struct.remove_const :Test
end
end
assert("Struct#initialize_copy requires struct to be the same type") do
begin
Struct.new("Test", :a)
a = Struct::Test.new("a")
Struct.remove_const :Test
Struct.new("Test", :a, :b)
assert_raise(TypeError) do
a.initialize_copy(Struct::Test.new("a", "b"))
end
ensure
Struct.remove_const :Test
end
end
assert("Struct.new does not allow array") do
assert_raise(TypeError) do
Struct.new("Test", [:a])
end
end
assert("Struct.new generates subclass of Struct") do
begin
original_struct = Struct
Struct = String
assert_equal original_struct, original_struct.new.superclass
ensure
Struct = original_struct
end
end
+6
View File
@@ -94,6 +94,12 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose)
mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN));
mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT));
#ifdef MRB_USE_FLOAT
mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-6));
#else
mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-12));
#endif
if (verbose) {
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value());
}
+69 -40
View File
@@ -183,7 +183,7 @@ static const struct mrb_data_type mrb_time_type = { "Time", mrb_free };
/** Updates the datetime of a mrb_time based on it's timezone and
seconds setting. Returns self on success, NULL of failure. */
static struct mrb_time*
mrb_time_update_datetime(struct mrb_time *self)
time_update_datetime(mrb_state *mrb, struct mrb_time *self)
{
struct tm *aid;
@@ -193,7 +193,11 @@ mrb_time_update_datetime(struct mrb_time *self)
else {
aid = localtime_r(&self->sec, &self->datetime);
}
if (!aid) return NULL;
if (!aid) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec));
/* not reached */
return NULL;
}
#ifdef NO_GMTIME_R
self->datetime = *aid; /* copy data */
#endif
@@ -213,7 +217,7 @@ static struct mrb_time*
time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
{
struct mrb_time *tm;
time_t tsec;
time_t tsec = 0;
if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
goto out_of_range;
@@ -238,7 +242,7 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
tm->usec -= 1000000;
}
tm->timezone = timezone;
mrb_time_update_datetime(tm);
time_update_datetime(mrb, tm);
return tm;
}
@@ -290,7 +294,7 @@ current_mrb_time(mrb_state *mrb)
}
#endif
tm->timezone = MRB_TIMEZONE_LOCAL;
mrb_time_update_datetime(tm);
time_update_datetime(mrb, tm);
return tm;
}
@@ -328,6 +332,15 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday,
nowtime.tm_min = (int)amin;
nowtime.tm_sec = (int)asec;
nowtime.tm_isdst = -1;
if (nowtime.tm_mon < 0 || nowtime.tm_mon > 11
|| nowtime.tm_mday < 1 || nowtime.tm_mday > 31
|| nowtime.tm_hour < 0 || nowtime.tm_hour > 24
|| (nowtime.tm_hour == 24 && (nowtime.tm_min > 0 || nowtime.tm_sec > 0))
|| nowtime.tm_min < 0 || nowtime.tm_min > 59
|| nowtime.tm_sec < 0 || nowtime.tm_sec > 60)
mrb_raise(mrb, E_RUNTIME_ERROR, "argument out of range");
if (timezone == MRB_TIMEZONE_UTC) {
nowsecs = timegm(&nowtime);
}
@@ -368,6 +381,17 @@ mrb_time_local(mrb_state *mrb, mrb_value self)
time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL));
}
static struct mrb_time*
time_get_ptr(mrb_state *mrb, mrb_value time)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, time, &mrb_time_type, struct mrb_time);
if (!tm) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time");
}
return tm;
}
static mrb_value
mrb_time_eq(mrb_state *mrb, mrb_value self)
@@ -377,7 +401,7 @@ mrb_time_eq(mrb_state *mrb, mrb_value self)
mrb_bool eq_p;
mrb_get_args(mrb, "o", &other);
tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
eq_p = tm1 && tm2 && tm1->sec == tm2->sec && tm1->usec == tm2->usec;
@@ -391,7 +415,7 @@ mrb_time_cmp(mrb_state *mrb, mrb_value self)
struct mrb_time *tm1, *tm2;
mrb_get_args(mrb, "o", &other);
tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
if (!tm1 || !tm2) return mrb_nil_value();
if (tm1->sec > tm2->sec) {
@@ -417,7 +441,7 @@ mrb_time_plus(mrb_state *mrb, mrb_value self)
struct mrb_time *tm;
mrb_get_args(mrb, "f", &f);
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone);
}
@@ -429,8 +453,7 @@ mrb_time_minus(mrb_state *mrb, mrb_value self)
struct mrb_time *tm, *tm2;
mrb_get_args(mrb, "o", &other);
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
if (tm2) {
f = (mrb_float)(tm->sec - tm2->sec)
@@ -450,7 +473,7 @@ mrb_time_wday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_wday);
}
@@ -461,7 +484,7 @@ mrb_time_yday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_yday + 1);
}
@@ -472,7 +495,7 @@ mrb_time_year(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_year + 1900);
}
@@ -483,7 +506,7 @@ mrb_time_zone(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
if (tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value();
if (tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value();
return mrb_str_new_static(mrb,
@@ -501,7 +524,7 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self)
char buf[256];
int len;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
d = &tm->datetime;
len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
@@ -518,8 +541,7 @@ mrb_time_day(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
if (!tm) return mrb_nil_value();
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mday);
}
@@ -531,7 +553,7 @@ mrb_time_dst_p(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_bool_value(tm->datetime.tm_isdst);
}
@@ -543,11 +565,11 @@ mrb_time_getutc(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm, *tm2;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_UTC;
mrb_time_update_datetime(tm2);
time_update_datetime(mrb, tm2);
return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
}
@@ -558,11 +580,11 @@ mrb_time_getlocal(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm, *tm2;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
*tm2 = *tm;
tm2->timezone = MRB_TIMEZONE_LOCAL;
mrb_time_update_datetime(tm2);
time_update_datetime(mrb, tm2);
return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
}
@@ -573,7 +595,7 @@ mrb_time_hour(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_hour);
}
@@ -587,14 +609,14 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self)
int n;
struct mrb_time *tm;
n = mrb_get_args(mrb, "|iiiiiii",
&ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
tm = (struct mrb_time*)DATA_PTR(self);
if (tm) {
mrb_free(mrb, tm);
}
mrb_data_init(self, NULL, &mrb_time_type);
n = mrb_get_args(mrb, "|iiiiiii",
&ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
if (n == 0) {
tm = current_mrb_time(mrb);
}
@@ -611,16 +633,23 @@ static mrb_value
mrb_time_initialize_copy(mrb_state *mrb, mrb_value copy)
{
mrb_value src;
struct mrb_time *t1, *t2;
mrb_get_args(mrb, "o", &src);
if (mrb_obj_equal(mrb, copy, src)) return copy;
if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) {
mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
}
if (!DATA_PTR(copy)) {
mrb_data_init(copy, mrb_malloc(mrb, sizeof(struct mrb_time)), &mrb_time_type);
t1 = (struct mrb_time *)DATA_PTR(copy);
t2 = (struct mrb_time *)DATA_PTR(src);
if (!t2) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time");
}
*(struct mrb_time *)DATA_PTR(copy) = *(struct mrb_time *)DATA_PTR(src);
if (!t1) {
t1 = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time));
mrb_data_init(copy, t1, &mrb_time_type);
}
*t1 = *t2;
return copy;
}
@@ -631,9 +660,9 @@ mrb_time_localtime(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_LOCAL;
mrb_time_update_datetime(tm);
time_update_datetime(mrb, tm);
return self;
}
@@ -644,7 +673,7 @@ mrb_time_mday(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mday);
}
@@ -655,7 +684,7 @@ mrb_time_min(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_min);
}
@@ -666,7 +695,7 @@ mrb_time_mon(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_mon + 1);
}
@@ -677,7 +706,7 @@ mrb_time_sec(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_fixnum_value(tm->datetime.tm_sec);
}
@@ -689,7 +718,7 @@ mrb_time_to_f(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6);
}
@@ -700,7 +729,7 @@ mrb_time_to_i(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) {
return mrb_float_value(mrb, (mrb_float)tm->sec);
}
@@ -714,7 +743,7 @@ mrb_time_usec(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) {
return mrb_float_value(mrb, (mrb_float)tm->usec);
}
@@ -728,9 +757,9 @@ mrb_time_utc(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
tm->timezone = MRB_TIMEZONE_UTC;
mrb_time_update_datetime(tm);
time_update_datetime(mrb, tm);
return self;
}
@@ -741,7 +770,7 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self)
{
struct mrb_time *tm;
tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
tm = time_get_ptr(mrb, self);
return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC);
}
+9 -30
View File
@@ -100,11 +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=nil, 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 num == nil
while true
block.call(i)
i+=step
end
return self
end
if step > 0
while i <= num
block.call(i)
@@ -160,35 +167,7 @@ end
#
# ISO 15.2.9
class Float
include Integral
# mruby special - since mruby integers may be upgraded to floats,
# floats should be compatible to integers.
def >> other
n = self.to_i
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 = other.to_i
if other < 0
n >> -other
else
other.times { n *= 2 }
n
end
end
include Integral
end
+11 -3
View File
@@ -159,16 +159,24 @@ class String
anum = args.size
if anum == 2
pos, value = args
if pos.kind_of? String
case pos
when 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
when Range
head = pos.begin
tail = pos.end
tail += self.length if tail < 0
unless pos.exclude_end?
tail += 1
end
return self[head, tail-head]=value
else
pos += self.length if pos < 0
if pos < 0 || pos > self.length
@@ -177,8 +185,8 @@ class String
b = self[0, pos.to_i]
a = self[pos + 1..-1]
self.replace([b, value, a].join(''))
return value
end
return value
elsif anum == 3
pos, len, value = args
pos += self.length if pos < 0
+108 -64
View File
@@ -16,28 +16,16 @@
#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
#define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
static inline mrb_value
ary_elt(mrb_value ary, mrb_int offset)
{
if (offset < 0 || RARRAY_LEN(ary) <= offset) {
return mrb_nil_value();
}
return RARRAY_PTR(ary)[offset];
}
static struct RArray*
ary_new_capa(mrb_state *mrb, mrb_int capa)
{
struct RArray *a;
mrb_int blen;
size_t blen;
if (capa > ARY_MAX_SIZE) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
blen = capa * sizeof(mrb_value);
if (blen < capa) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
a->ptr = (mrb_value *)mrb_malloc(mrb, blen);
@@ -120,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void
ary_modify(mrb_state *mrb, struct RArray *a)
{
if (MRB_FROZEN_P(a)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
}
if (ARY_SHARED_P(a)) {
mrb_shared_array *shared = a->aux.shared;
@@ -130,7 +122,7 @@ ary_modify(mrb_state *mrb, struct RArray *a)
}
else {
mrb_value *ptr, *p;
mrb_int len;
size_t len;
p = a->ptr;
len = a->len * sizeof(mrb_value);
@@ -173,11 +165,12 @@ ary_make_shared(mrb_state *mrb, struct RArray *a)
}
static void
ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len)
{
mrb_int capa = a->aux.capa;
size_t capa = a->aux.capa;
if (len > ARY_MAX_SIZE) {
size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
@@ -185,12 +178,18 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
capa = ARY_DEFAULT_LEN;
}
while (capa < len) {
capa *= 2;
if (capa <= ARY_MAX_SIZE / 2) {
capa *= 2;
}
else {
capa = len;
}
}
if (capa < len || capa > ARY_MAX_SIZE) {
goto size_error;
}
if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
if (capa > a->aux.capa) {
if (capa > (size_t)a->aux.capa) {
mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
a->aux.capa = capa;
@@ -254,13 +253,20 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self)
}
static void
ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen)
ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
{
mrb_int len = a->len + blen;
mrb_int len;
if (a2->len > ARY_MAX_SIZE - a->len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
len = a->len + a2->len;
ary_modify(mrb, a);
if (a->aux.capa < len) ary_expand_capa(mrb, a, len);
array_copy(a->ptr+a->len, ptr, blen);
if (a->aux.capa < len) {
ary_expand_capa(mrb, a, len);
}
array_copy(a->ptr+a->len, a2->ptr, a2->len);
mrb_write_barrier(mrb, (struct RBasic*)a);
a->len = len;
}
@@ -270,17 +276,16 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RArray *a2 = mrb_ary_ptr(other);
ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
ary_concat(mrb, mrb_ary_ptr(self), a2);
}
static mrb_value
mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
{
mrb_value *ptr;
mrb_int blen;
mrb_value ary;
mrb_get_args(mrb, "a", &ptr, &blen);
ary_concat(mrb, mrb_ary_ptr(self), ptr, blen);
mrb_get_args(mrb, "A", &ary);
mrb_ary_concat(mrb, self, ary);
return self;
}
@@ -318,9 +323,12 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
MRB_API void
mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2 = mrb_ary_ptr(other);
ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
if (a1 != a2) {
ary_replace(mrb, a1, a2->ptr, a2->len);
}
}
static mrb_value
@@ -432,6 +440,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
struct RArray *a = mrb_ary_ptr(ary);
ary_modify(mrb, a);
if (a->len == 0) return mrb_nil_value();
return a->ptr[--a->len];
}
@@ -444,6 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
struct RArray *a = mrb_ary_ptr(self);
mrb_value val;
ary_modify(mrb, a);
if (a->len == 0) return mrb_nil_value();
if (ARY_SHARED_P(a)) {
L_SHIFT:
@@ -506,6 +516,9 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
mrb_int len;
mrb_get_args(mrb, "*", &vals, &len);
if (len > ARY_MAX_SIZE - a->len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
if (ARY_SHARED_P(a)
&& a->aux.shared->refcnt == 1 /* shared only referenced from this array */
&& a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
@@ -563,13 +576,22 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
static struct RArray*
ary_dup(mrb_state *mrb, struct RArray *a)
{
struct RArray *d = ary_new_capa(mrb, a->len);
ary_replace(mrb, d, a->ptr, a->len);
return d;
}
MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
mrb_int tail, size;
const mrb_value *argv;
mrb_int i, argc;
mrb_int argc;
size_t tail;
ary_modify(mrb, a);
@@ -583,40 +605,59 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
}
}
if (a->len < len || a->len < head + len) {
tail = head + len;
if (a->len < len || (size_t)a->len < tail) {
len = a->len - head;
}
tail = head + len;
/* size check */
if (mrb_array_p(rpl)) {
argc = RARRAY_LEN(rpl);
argv = RARRAY_PTR(rpl);
if (argv == a->ptr) {
struct RArray *r = ary_dup(mrb, a);
argv = r->ptr;
}
}
else {
argc = 1;
argv = &rpl;
}
size = head + argc;
if (tail < a->len) size += a->len - tail;
if (size > a->aux.capa)
ary_expand_capa(mrb, a, size);
if (head > a->len) {
if (head >= a->len) {
if (head > ARY_MAX_SIZE - argc) {
mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
}
len = head + argc;
if (len > a->aux.capa) {
ary_expand_capa(mrb, a, head + argc);
}
ary_fill_with_nil(a->ptr + a->len, head - a->len);
if (argc > 0) {
array_copy(a->ptr + head, argv, argc);
}
a->len = len;
}
else if (head < a->len) {
value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
else {
mrb_int alen;
if (a->len - len > ARY_MAX_SIZE - argc) {
mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len));
}
alen = a->len + argc - len;
if (alen > a->aux.capa) {
ary_expand_capa(mrb, a, alen);
}
if (len != argc) {
tail = head + len;
value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
a->len = alen;
}
if (argc > 0) {
value_move(a->ptr + head, argv, argc);
}
}
for (i = 0; i < argc; i++) {
*(a->ptr + head + i) = *(argv + i);
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]);
}
a->len = size;
mrb_write_barrier(mrb, (struct RBasic*)a);
return ary;
}
@@ -702,7 +743,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self)
switch (mrb_type(index)) {
/* a[n..m] */
case MRB_TT_RANGE:
if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) {
if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
return ary_subseq(mrb, a, i, len);
}
else {
@@ -766,21 +807,19 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self)
mrb_value v1, v2, v3;
mrb_int i, len;
mrb_ary_modify(mrb, mrb_ary_ptr(self));
if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) {
switch (mrb_type(v1)) {
/* a[n..m] = v */
case MRB_TT_RANGE:
if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) {
mrb_ary_splice(mrb, self, i, len, v2);
}
break;
/* a[n] = v */
case MRB_TT_FIXNUM:
mrb_ary_set(mrb, self, mrb_fixnum(v1), v2);
break;
default:
switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) {
case 0: /* not range */
mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
break;
case 1: /* range */
mrb_ary_splice(mrb, self, i, len, v2);
break;
case 2: /* out of range */
mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
break;
}
return v2;
}
@@ -877,13 +916,16 @@ static mrb_value
mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
{
mrb_value obj;
mrb_int i;
mrb_int i, len;
mrb_get_args(mrb, "o", &obj);
for (i = RARRAY_LEN(self) - 1; i >= 0; i--) {
if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
return mrb_fixnum_value(i);
}
if (i > (len = RARRAY_LEN(self))) {
i = len;
}
}
return mrb_nil_value();
}
@@ -915,6 +957,7 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v)
recv_class,
mrb_obj_value(mrb_obj_class(mrb, a))
);
/* not reached */
return mrb_undef_value();
}
}
@@ -932,6 +975,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
ary_modify(mrb, a);
if (ARY_SHARED_P(a)) {
mrb_ary_decref(mrb, a->aux.shared);
ARY_UNSET_SHARED_FLAG(a);
+7 -4
View File
@@ -118,6 +118,7 @@ each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func
if (MRB_PROC_CFUNC_P(ci->proc)) continue;
irep = ci->proc->body.irep;
if (!irep) continue;
if (mrb->c->cibase[i].err) {
pc = mrb->c->cibase[i].err;
@@ -160,7 +161,7 @@ static void
output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data)
{
struct backtrace_location loc;
struct output_backtrace_args *args = data;
struct output_backtrace_args *args = (struct output_backtrace_args *)data;
loc.i = loc_raw->i;
loc.lineno = loc_raw->lineno;
@@ -219,7 +220,9 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
for (i = 0; i < n; i++) {
mrb_value entry = RARRAY_PTR(backtrace)[i];
fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
if (mrb_string_p(entry)) {
fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
}
}
}
@@ -260,7 +263,7 @@ mrb_print_backtrace(mrb_state *mrb)
{
mrb_value backtrace;
if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
if (!mrb->exc) {
return;
}
@@ -338,7 +341,7 @@ save_backtrace_i(mrb_state *mrb,
else {
new_n_allocated = mrb->backtrace.n_allocated * 2;
}
mrb->backtrace.entries =
mrb->backtrace.entries = (mrb_backtrace_entry *)
mrb_realloc(mrb,
mrb->backtrace.entries,
sizeof(mrb_backtrace_entry) * new_n_allocated);
+161 -75
View File
@@ -14,6 +14,7 @@
#include <mruby/variable.h>
#include <mruby/error.h>
#include <mruby/data.h>
#include <mruby/istruct.h>
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -174,6 +175,14 @@ MRB_API struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
check_if_class_or_module(mrb, outer);
if (mrb_const_defined_at(mrb, outer, id)) {
mrb_value old = mrb_const_get(mrb, outer, id);
if (mrb_type(old) != MRB_TT_MODULE) {
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old));
}
return mrb_class_ptr(old);
}
return define_module(mrb, id, mrb_class_ptr(outer));
}
@@ -231,12 +240,22 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
}
static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv);
static void
mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
{
mrb_value s;
mrb_sym mid;
if (!super)
super = mrb->object_class;
mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
s = mrb_obj_value(super);
mid = mrb_intern_lit(mrb, "inherited");
if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) {
mrb_value c = mrb_obj_value(klass);
mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c);
}
}
MRB_API struct RClass*
@@ -255,6 +274,21 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
s = 0;
}
check_if_class_or_module(mrb, outer);
if (mrb_const_defined_at(mrb, outer, id)) {
mrb_value old = mrb_const_get(mrb, outer, id);
if (mrb_type(old) != MRB_TT_CLASS) {
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old));
}
c = mrb_class_ptr(old);
if (s) {
/* check super class */
if (mrb_class_real(c->super) != s) {
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old);
}
}
return c;
}
c = define_class(mrb, id, s, mrb_class_ptr(outer));
mrb_class_inherited(mrb, mrb_class_real(c->super), c);
@@ -272,7 +306,7 @@ mrb_class_defined(mrb_state *mrb, const char *name)
}
MRB_API mrb_bool
mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name)
mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
mrb_value sym = mrb_check_intern_cstr(mrb, name);
if (mrb_nil_p(sym)) {
@@ -293,6 +327,20 @@ mrb_class_get(mrb_state *mrb, const char *name)
return mrb_class_get_under(mrb, mrb->object_class, name);
}
MRB_API struct RClass *
mrb_exc_get(mrb_state *mrb, const char *name)
{
struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name);
struct RClass *e = exc;
while (e) {
if (e == mrb->eException_class)
return exc;
e = e->super;
}
return mrb->eException_class;
}
MRB_API struct RClass *
mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
@@ -346,6 +394,12 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
MRB_CLASS_ORIGIN(c);
h = c->mt;
if (MRB_FROZEN_P(c)) {
if (c->tt == MRB_TT_MODULE)
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module");
else
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class");
}
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
kh_value(h, k) = p;
@@ -468,6 +522,7 @@ to_sym(mrb_state *mrb, mrb_value ss)
b: Boolean [mrb_bool]
n: Symbol [mrb_sym]
d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
I: Inline struct [void*]
&: Block [mrb_value]
*: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
@@ -679,6 +734,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
break;
case 'I':
{
void* *p;
mrb_value ss;
p = va_arg(ap, void**);
if (i < argc) {
ss = ARGV[arg_i];
if (mrb_type(ss) != MRB_TT_ISTRUCT)
{
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss);
}
*p = mrb_istruct_ptr(ss);
arg_i++;
i++;
}
}
break;
case 'f':
{
mrb_float *p;
@@ -852,7 +925,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
static void
boot_initmod(mrb_state *mrb, struct RClass *mod)
{
mod->mt = kh_init(mt, mrb);
if (!mod->mt) {
mod->mt = kh_init(mt, mrb);
}
}
static struct RClass*
@@ -1305,6 +1380,9 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");
if (ttype == 0) ttype = MRB_TT_OBJECT;
if (ttype <= MRB_TT_CPTR) {
mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv);
}
o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
return mrb_obj_value(o);
}
@@ -1339,10 +1417,13 @@ MRB_API mrb_value
mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
{
mrb_value obj;
mrb_sym mid;
obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv);
mid = mrb_intern_lit(mrb, "initialize");
if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) {
mrb_funcall_argv(mrb, obj, mid, argc, argv);
}
return obj;
}
@@ -1364,13 +1445,17 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
mrb_int n;
mrb_value super, blk;
mrb_value new_class;
mrb_sym mid;
n = mrb_get_args(mrb, "|C&", &super, &blk);
if (n == 0) {
super = mrb_obj_value(mrb->object_class);
}
new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk);
mid = mrb_intern_lit(mrb, "initialize");
if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) {
mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
}
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
return new_class;
}
@@ -1401,75 +1486,53 @@ 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 */
/* 15.3.1.3.1 */
/* 15.3.1.3.10 */
/* 15.3.1.3.11 */
/*
* call-seq:
* obj.method_missing(symbol [, *args] ) -> result
* obj == other -> true or false
* obj.equal?(other) -> true or false
* obj.eql?(other) -> true or false
*
* Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
* <i>symbol</i> is the symbol for the method called, and <i>args</i>
* are any arguments that were passed to it. By default, the interpreter
* raises an error when this method is called. However, it is possible
* to override the method to provide more dynamic behavior.
* If it is decided that a particular method should not be handled, then
* <i>super</i> should be called, so that ancestors can pick up the
* missing method.
* The example below creates
* a class <code>Roman</code>, which responds to methods with names
* consisting of roman numerals, returning the corresponding integer
* values.
* Equality---At the <code>Object</code> level, <code>==</code> returns
* <code>true</code> only if <i>obj</i> and <i>other</i> are the
* same object. Typically, this method is overridden in descendant
* classes to provide class-specific meaning.
*
* class Roman
* def romanToInt(str)
* # ...
* end
* def method_missing(methId)
* str = methId.id2name
* romanToInt(str)
* end
* end
* Unlike <code>==</code>, the <code>equal?</code> method should never be
* overridden by subclasses: it is used to determine object identity
* (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
* object as <code>b</code>).
*
* r = Roman.new
* r.iv #=> 4
* r.xxiii #=> 23
* r.mm #=> 2000
* The <code>eql?</code> method returns <code>true</code> if
* <i>obj</i> and <i>anObject</i> have the same value. Used by
* <code>Hash</code> to test members for equality. For objects of
* class <code>Object</code>, <code>eql?</code> is synonymous with
* <code>==</code>. Subclasses normally continue this tradition, but
* there are exceptions. <code>Numeric</code> types, for example,
* perform type conversion across <code>==</code>, but not across
* <code>eql?</code>, so:
*
* 1 == 1.0 #=> true
* 1.eql? 1.0 #=> false
*/
static mrb_value
mrb_bob_missing(mrb_state *mrb, mrb_value mod)
mrb_value
mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
{
mrb_sym name;
mrb_value *a;
mrb_int alen;
mrb_value arg;
mrb_get_args(mrb, "n*", &name, &a, &alen);
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
return mrb_nil_value();
mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
}
static mrb_value
mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
{
mrb_value arg;
mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(!mrb_equal(mrb, self, arg));
}
MRB_API mrb_bool
@@ -1518,7 +1581,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
if (sym == 0) {
return mrb_nil_value();
}
else if (outer && outer != mrb->object_class) {
else if (outer && outer != c && outer != mrb->object_class) {
mrb_value base = mrb_class_path(mrb, outer);
path = mrb_str_buf_new(mrb, 0);
if (mrb_nil_p(base)) {
@@ -1537,9 +1600,11 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
name = mrb_sym2name_len(mrb, sym, &len);
path = mrb_str_new(mrb, name, len);
}
mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
if (!MRB_FROZEN_P(c)) {
mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
}
}
return path;
return mrb_str_dup(mrb, path);
}
MRB_API struct RClass *
@@ -1771,7 +1836,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
undef_method(mrb, c, mrb_symbol(*argv));
undef_method(mrb, c, to_sym(mrb, *argv));
argv++;
}
return mrb_nil_value();
@@ -1783,9 +1848,21 @@ mod_define_method(mrb_state *mrb, mrb_value self)
struct RClass *c = mrb_class_ptr(self);
struct RProc *p;
mrb_sym mid;
mrb_value proc = mrb_undef_value();
mrb_value blk;
mrb_get_args(mrb, "n&", &mid, &blk);
mrb_get_args(mrb, "n|o&", &mid, &proc, &blk);
switch (mrb_type(proc)) {
case MRB_TT_PROC:
blk = proc;
break;
case MRB_TT_UNDEF:
/* ignored */
break;
default:
mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc)));
break;
}
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
@@ -2013,7 +2090,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
remove_method(mrb, mod, mrb_symbol(*argv));
remove_method(mrb, mod, to_sym(mrb, *argv));
argv++;
}
return mod;
@@ -2168,6 +2245,11 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
return mod;
}
/* implementation of __id__ */
mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
/* implementation of instance_eval */
mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
void
mrb_init_class(mrb_state *mrb)
{
@@ -2207,7 +2289,11 @@ mrb_init_class(mrb_state *mrb)
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
@@ -2252,7 +2338,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1));
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
+1 -2
View File
@@ -416,8 +416,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv(mrb, irep, c, RA);
break;
case OP_POPERR:
printf("OP_POPERR\t%d\t\t", GETARG_A(c));
print_lv(mrb, irep, c, RA);
printf("OP_POPERR\t%d\t\t\n", GETARG_A(c));
break;
case OP_EPOP:
printf("OP_EPOP\t%d\n", GETARG_A(c));
+2
View File
@@ -1059,6 +1059,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
return MRB_DUMP_WRITE_FAULT;
}
if (fprintf(fp,
"extern const uint8_t %s[];\n"
"const uint8_t\n"
"#if defined __GNUC__\n"
"__attribute__((aligned(%u)))\n"
@@ -1066,6 +1067,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con
"__declspec(align(%u))\n"
"#endif\n"
"%s[] = {",
initname,
(uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
+33 -12
View File
@@ -44,8 +44,10 @@ static mrb_value
exc_initialize(mrb_state *mrb, mrb_value exc)
{
mrb_value mesg;
mrb_int argc;
mrb_value *argv;
if (mrb_get_args(mrb, "|o", &mesg) == 1) {
if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) {
mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
}
return exc;
@@ -200,14 +202,32 @@ exc_get_backtrace(mrb_state *mrb, mrb_value exc)
return backtrace;
}
static void
set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
{
if (!mrb_array_p(backtrace)) {
type_err:
mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
}
else {
const mrb_value *p = RARRAY_PTR(backtrace);
const mrb_value *pend = p + RARRAY_LEN(backtrace);
while (p < pend) {
if (!mrb_string_p(*p)) goto type_err;
p++;
}
}
mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
}
static mrb_value
exc_set_backtrace(mrb_state *mrb, mrb_value exc)
{
mrb_value backtrace;
mrb_get_args(mrb, "o", &backtrace);
mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
set_backtrace(mrb, exc, backtrace);
return backtrace;
}
@@ -238,12 +258,6 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
}
}
static void
set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
{
mrb_funcall(mrb, info, "set_backtrace", 1, bt);
}
static mrb_bool
have_backtrace(mrb_state *mrb, struct RObject *exc)
{
@@ -285,6 +299,9 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
MRB_API mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
}
mrb_exc_set(mrb, exc);
if (!mrb->gc.out_of_memory) {
exc_debug_info(mrb, mrb->exc);
@@ -463,7 +480,7 @@ exception_call:
}
if (argc > 0) {
if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
mrb_raise(mrb, mrb->eException_class, "exception object expected");
if (argc > 2)
set_backtrace(mrb, mesg, argv[2]);
}
@@ -514,7 +531,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt,
void
mrb_init_exception(mrb_state *mrb)
{
struct RClass *exception, *runtime_error, *script_error;
struct RClass *exception, *runtime_error, *script_error, *stack_error;
mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
@@ -530,7 +547,11 @@ mrb_init_exception(mrb_state *mrb)
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory"));
#ifdef MRB_GC_FIXED_ARENA
mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "arena overflow error"));
#endif
script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
mrb_define_class(mrb, "SystemStackError", exception);
stack_error = mrb_define_class(mrb, "SystemStackError", exception);
mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
}
+1
View File
@@ -139,6 +139,7 @@ mrb_obj_id(mrb_value obj)
case MRB_TT_EXCEPTION:
case MRB_TT_FILE:
case MRB_TT_DATA:
case MRB_TT_ISTRUCT:
default:
return MakeID(mrb_ptr(obj));
}
+76 -18
View File
@@ -367,7 +367,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
#endif
}
static void obj_free(mrb_state *mrb, struct RBasic *obj);
static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
void
free_heap(mrb_state *mrb, mrb_gc *gc)
@@ -381,7 +381,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc)
page = page->next;
for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
if (p->as.free.tt != MRB_TT_FREE)
obj_free(mrb, &p->as.basic);
obj_free(mrb, &p->as.basic, TRUE);
}
mrb_free(mrb, tmp);
}
@@ -403,7 +403,7 @@ gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
/* arena overflow error */
gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err));
}
#else
if (gc->arena_idx >= gc->arena_capa) {
@@ -453,7 +453,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
mrb_value table = mrb_gv_get(mrb, root);
struct RArray *a;
mrb_int i, len;
mrb_int i;
if (mrb_nil_p(table)) return;
if (mrb_type(table) != MRB_TT_ARRAY) {
@@ -462,14 +462,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
}
a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
len = a->len-1;
for (i=0; i<len; i++) {
for (i = 0; i < a->len; i++) {
if (mrb_obj_eq(mrb, a->ptr[i], obj)) {
memmove(&a->ptr[i], &a->ptr[i+1], len-i);
a->len--;
memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i]));
break;
}
}
a->len--;
}
MRB_API struct RBasic*
@@ -479,6 +478,28 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
mrb_gc *gc = &mrb->gc;
if (cls) {
enum mrb_vtype tt;
switch (cls->tt) {
case MRB_TT_CLASS:
case MRB_TT_SCLASS:
case MRB_TT_MODULE:
case MRB_TT_ENV:
break;
default:
mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
}
tt = MRB_INSTANCE_TT(cls);
if (tt != MRB_TT_FALSE &&
ttype != MRB_TT_SCLASS &&
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != tt) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
}
}
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
#endif
@@ -678,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
}
static void
obj_free(mrb_state *mrb, struct RBasic *obj)
obj_free(mrb_state *mrb, struct RBasic *obj, int end)
{
DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt));
switch (obj->tt) {
@@ -720,17 +741,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
{
struct REnv *e = (struct REnv*)obj;
if (!MRB_ENV_STACK_SHARED_P(e)) {
mrb_free(mrb, e->stack);
e->stack = NULL;
if (MRB_ENV_STACK_SHARED_P(e)) {
/* cannot be freed */
return;
}
mrb_free(mrb, e->stack);
e->stack = NULL;
}
break;
case MRB_TT_FIBER:
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
if (c && c != mrb->root_c) {
if (!end && c && c != mrb->root_c) {
mrb_callinfo *ci = c->ci;
mrb_callinfo *ce = c->cibase;
@@ -810,12 +833,42 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc)
}
/* mark class hierarchy */
mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
/* mark built-in classes */
mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module);
mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class);
mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class);
/* mark top_self */
mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
/* mark exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
/* mark backtrace */
mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc);
e = (size_t)mrb->backtrace.n;
for (i=0; i<e; i++) {
mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.entries[i].klass);
}
/* mark pre-allocated exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err);
#ifdef MRB_GC_FIXED_ARENA
mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err);
#endif
mark_context(mrb, mrb->root_c);
if (mrb->root_c->fib) {
@@ -973,16 +1026,21 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
while (p<e) {
if (is_dead(gc, &p->as.basic)) {
if (p->as.basic.tt != MRB_TT_FREE) {
obj_free(mrb, &p->as.basic);
p->as.free.next = page->freelist;
page->freelist = (struct RBasic*)p;
freed++;
obj_free(mrb, &p->as.basic, FALSE);
if (p->as.basic.tt == MRB_TT_FREE) {
p->as.free.next = page->freelist;
page->freelist = (struct RBasic*)p;
freed++;
}
else {
dead_slot = FALSE;
}
}
}
else {
if (!is_generational(gc))
paint_partial_white(gc, &p->as.basic); /* next gc target */
dead_slot = 0;
dead_slot = FALSE;
}
p++;
}
+52 -16
View File
@@ -98,9 +98,9 @@ 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) && !RSTR_FROZEN_P(mrb_str_ptr(key))) {
if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) {
key = mrb_str_dup(mrb, key);
RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key));
MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
}
return key;
}
@@ -159,11 +159,15 @@ mrb_hash_new(mrb_state *mrb)
return mrb_hash_new_capa(mrb, 0);
}
static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
mrb_sym mid;
if (h) {
k = kh_get(ht, mrb, h, key);
@@ -171,14 +175,12 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
return kh_value(h, k).v;
}
/* not found */
if (MRB_RHASH_DEFAULT_P(hash)) {
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
return RHASH_IFNONE(hash);
mid = mrb_intern_lit(mrb, "default");
if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
return hash_default(mrb, hash, key);
}
return mrb_nil_value();
/* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
return mrb_funcall_argv(mrb, hash, mid, 1, &key);
}
MRB_API mrb_value
@@ -230,6 +232,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
struct RHash* ret;
khash_t(ht) *h, *ret_h;
khiter_t k, ret_k;
mrb_value ifnone, vret;
h = RHASH_TBL(hash);
ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
@@ -248,7 +251,18 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
}
}
return mrb_obj_value(ret);
if (MRB_RHASH_DEFAULT_P(hash)) {
ret->flags |= MRB_HASH_DEFAULT;
}
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
ret->flags |= MRB_HASH_PROC_DEFAULT;
}
vret = mrb_obj_value(ret);
ifnone = RHASH_IFNONE(hash);
if (!mrb_nil_p(ifnone)) {
mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
}
return vret;
}
MRB_API mrb_value
@@ -271,6 +285,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
{
if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash");
}
mrb_hash_tbl(mrb, hash);
}
@@ -356,6 +373,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
return mrb_hash_get(mrb, self, key);
}
static mrb_value
hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
{
if (MRB_RHASH_DEFAULT_P(hash)) {
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
else {
return RHASH_IFNONE(hash);
}
}
return mrb_nil_value();
}
/* 15.2.13.4.5 */
/*
* call-seq:
@@ -385,13 +416,16 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash)
mrb_bool given;
mrb_get_args(mrb, "|o?", &key, &given);
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
if (!given) return mrb_nil_value();
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
else {
return RHASH_IFNONE(hash);
if (MRB_RHASH_DEFAULT_P(hash)) {
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
if (!given) return mrb_nil_value();
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
else {
return RHASH_IFNONE(hash);
}
}
return mrb_nil_value();
}
/* 15.2.13.4.6 */
@@ -541,6 +575,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
mrb_value key;
mrb_get_args(mrb, "o", &key);
mrb_hash_modify(mrb, self);
return mrb_hash_delete_key(mrb, self, key);
}
@@ -607,6 +642,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
mrb_hash_modify(mrb, hash);
if (h) kh_clear(ht, mrb, h);
return hash;
}
+153 -70
View File
@@ -6,11 +6,13 @@
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/hash.h>
#include <mruby/class.h>
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/variable.h>
#include <mruby/error.h>
#include <mruby/istruct.h>
typedef enum {
NOEX_PUBLIC = 0x00,
@@ -26,13 +28,19 @@ typedef enum {
NOEX_RESPONDS = 0x80
} mrb_method_flag_t;
MRB_API mrb_bool
mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
{
struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid);
if (MRB_PROC_CFUNC_P(me) && (me->body.func == func))
return TRUE;
return FALSE;
}
static mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
return TRUE;
return FALSE;
return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s);
}
/* 15.3.1.3.17 */
@@ -58,55 +66,6 @@ mrb_obj_inspect(mrb_state *mrb, mrb_value obj)
return mrb_any_to_s(mrb, obj);
}
/* 15.3.1.3.1 */
/* 15.3.1.3.10 */
/* 15.3.1.3.11 */
/*
* call-seq:
* obj == other -> true or false
* obj.equal?(other) -> true or false
* obj.eql?(other) -> true or false
*
* Equality---At the <code>Object</code> level, <code>==</code> returns
* <code>true</code> only if <i>obj</i> and <i>other</i> are the
* same object. Typically, this method is overridden in descendant
* classes to provide class-specific meaning.
*
* Unlike <code>==</code>, the <code>equal?</code> method should never be
* overridden by subclasses: it is used to determine object identity
* (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same
* object as <code>b</code>).
*
* The <code>eql?</code> method returns <code>true</code> if
* <i>obj</i> and <i>anObject</i> have the same value. Used by
* <code>Hash</code> to test members for equality. For objects of
* class <code>Object</code>, <code>eql?</code> is synonymous with
* <code>==</code>. Subclasses normally continue this tradition, but
* there are exceptions. <code>Numeric</code> types, for example,
* perform type conversion across <code>==</code>, but not across
* <code>eql?</code>, so:
*
* 1 == 1.0 #=> true
* 1.eql? 1.0 #=> false
*/
static mrb_value
mrb_obj_equal_m(mrb_state *mrb, mrb_value self)
{
mrb_value arg;
mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(mrb_obj_equal(mrb, self, arg));
}
static mrb_value
mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self)
{
mrb_value arg;
mrb_get_args(mrb, "o", &arg);
return mrb_bool_value(!mrb_equal(mrb, self, arg));
}
/* 15.3.1.3.2 */
/*
* call-seq:
@@ -142,7 +101,7 @@ mrb_equal_m(mrb_state *mrb, mrb_value self)
* <code>:name</code> notation, which returns the symbol id of
* <code>name</code>. Replaces the deprecated <code>Object#id</code>.
*/
static mrb_value
mrb_value
mrb_obj_id_m(mrb_state *mrb, mrb_value self)
{
return mrb_fixnum_value(mrb_obj_id(self));
@@ -284,6 +243,7 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
}
dc->mt = kh_copy(mt, mrb, sc->mt);
dc->super = sc->super;
MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc));
}
static void
@@ -301,6 +261,9 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
case MRB_TT_EXCEPTION:
mrb_iv_copy(mrb, dest, obj);
break;
case MRB_TT_ISTRUCT:
mrb_istruct_copy(dest, obj);
break;
default:
break;
@@ -440,11 +403,60 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
{
mrb_value *argv;
mrb_int argc;
mrb_value args;
mrb_get_args(mrb, "*", &argv, &argc);
args = mrb_ary_new_from_values(mrb, argc, argv);
argv = (mrb_value*)RARRAY_PTR(args);
return mrb_obj_extend(mrb, argc, argv, self);
}
static mrb_value
mrb_obj_freeze(mrb_state *mrb, mrb_value self)
{
struct RBasic *b;
switch (mrb_type(self)) {
case MRB_TT_FALSE:
case MRB_TT_TRUE:
case MRB_TT_FIXNUM:
case MRB_TT_SYMBOL:
case MRB_TT_FLOAT:
return self;
default:
break;
}
b = mrb_basic_ptr(self);
if (!MRB_FROZEN_P(b)) {
MRB_SET_FROZEN_FLAG(b);
}
return self;
}
static mrb_value
mrb_obj_frozen(mrb_state *mrb, mrb_value self)
{
struct RBasic *b;
switch (mrb_type(self)) {
case MRB_TT_FALSE:
case MRB_TT_TRUE:
case MRB_TT_FIXNUM:
case MRB_TT_SYMBOL:
case MRB_TT_FLOAT:
return mrb_true_value();
default:
break;
}
b = mrb_basic_ptr(self);
if (!MRB_FROZEN_P(b)) {
return mrb_false_value();
}
return mrb_true_value();
}
/* 15.3.1.3.15 */
/*
* call-seq:
@@ -477,9 +489,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
}
/* implementation of instance_eval */
mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
MRB_API mrb_bool
mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
{
@@ -902,6 +911,77 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
return val;
}
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:
* obj.method_missing(symbol [, *args] ) -> result
*
* Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
* <i>symbol</i> is the symbol for the method called, and <i>args</i>
* are any arguments that were passed to it. By default, the interpreter
* raises an error when this method is called. However, it is possible
* to override the method to provide more dynamic behavior.
* If it is decided that a particular method should not be handled, then
* <i>super</i> should be called, so that ancestors can pick up the
* missing method.
* The example below creates
* a class <code>Roman</code>, which responds to methods with names
* consisting of roman numerals, returning the corresponding integer
* values.
*
* class Roman
* def romanToInt(str)
* # ...
* end
* def method_missing(methId)
* str = methId.id2name
* romanToInt(str)
* end
* end
*
* r = Roman.new
* r.iv #=> 4
* r.xxiii #=> 23
* r.mm #=> 2000
*/
static mrb_value
mrb_obj_missing(mrb_state *mrb, mrb_value mod)
{
mrb_sym name;
mrb_value *a;
mrb_int alen;
mrb_get_args(mrb, "n*", &name, &a, &alen);
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
return mrb_nil_value();
}
static inline mrb_bool
basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub)
{
@@ -937,14 +1017,17 @@ obj_respond_to(mrb_state *mrb, mrb_value self)
}
else {
mrb_value tmp;
if (!mrb_string_p(mid)) {
if (mrb_string_p(mid)) {
tmp = mrb_check_intern_str(mrb, mid);
}
else {
tmp = mrb_check_string_type(mrb, mid);
if (mrb_nil_p(tmp)) {
tmp = mrb_inspect(mrb, mid);
mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp);
}
tmp = mrb_check_intern_str(mrb, tmp);
}
tmp = mrb_check_intern_str(mrb, mid);
if (mrb_nil_p(tmp)) {
respond_to_p = FALSE;
}
@@ -1049,8 +1132,8 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_local_variables(mrb_state *mrb, mrb_value self)
{
mrb_value ret;
struct RProc *proc;
mrb_value vars;
struct mrb_irep *irep;
size_t i;
@@ -1064,22 +1147,23 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
if (!irep->lv) {
return mrb_ary_new(mrb);
}
ret = mrb_ary_new_capa(mrb, irep->nlocals - 1);
vars = mrb_hash_new(mrb);
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name));
mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
}
}
if (proc->env) {
struct REnv *e = proc->env;
while (e) {
if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) {
if (MRB_ENV_STACK_SHARED_P(e) &&
!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) {
irep = mrb->c->cibase[e->cioff].proc->body.irep;
if (irep->lv) {
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name));
mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
}
}
}
@@ -1088,9 +1172,10 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
}
}
return ret;
return mrb_hash_keys(mrb, vars);
}
mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value);
void
mrb_init_kernel(mrb_state *mrb)
{
@@ -1106,11 +1191,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */
mrb_define_method(mrb, krn, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1));
mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */
mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */
mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */
mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */
mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */
mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */
@@ -1118,11 +1199,12 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */
mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */
mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE());
mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */
mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */
mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */
mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */
mrb_define_method(mrb, krn, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */
mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */
mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */
mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */
@@ -1132,6 +1214,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
+145 -34
View File
@@ -13,8 +13,10 @@
#include <mruby/array.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
#ifdef MRB_USE_FLOAT
#define trunc(f) truncf(f)
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
@@ -271,6 +273,128 @@ flo_eq(mrb_state *mrb, mrb_value x)
}
}
static int64_t
value_int64(mrb_state *mrb, mrb_value x)
{
switch (mrb_type(x)) {
case MRB_TT_FIXNUM:
return (int64_t)mrb_fixnum(x);
break;
case MRB_TT_FLOAT:
return (int64_t)mrb_float(x);
default:
mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
break;
}
/* not reached */
return 0;
}
static mrb_value
int64_value(mrb_state *mrb, int64_t v)
{
if (FIXABLE(v)) {
return mrb_fixnum_value((mrb_int)v);
}
return mrb_float_value(mrb, (mrb_float)v);
}
static mrb_value
flo_rev(mrb_state *mrb, mrb_value x)
{
int64_t v1;
mrb_get_args(mrb, "");
v1 = (int64_t)mrb_float(x);
return int64_value(mrb, ~v1);
}
static mrb_value
flo_and(mrb_state *mrb, mrb_value x)
{
mrb_value y;
int64_t v1, v2;
mrb_get_args(mrb, "o", &y);
v1 = (int64_t)mrb_float(x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 & v2);
}
static mrb_value
flo_or(mrb_state *mrb, mrb_value x)
{
mrb_value y;
int64_t v1, v2;
mrb_get_args(mrb, "o", &y);
v1 = (int64_t)mrb_float(x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 | v2);
}
static mrb_value
flo_xor(mrb_state *mrb, mrb_value x)
{
mrb_value y;
int64_t v1, v2;
mrb_get_args(mrb, "o", &y);
v1 = (int64_t)mrb_float(x);
v2 = value_int64(mrb, y);
return int64_value(mrb, v1 ^ v2);
}
static mrb_value
flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
{
mrb_float val;
if (width == 0) {
return x;
}
val = mrb_float(x);
if (width < 0) {
while (width++) {
val /= 2;
}
#if defined(_ISOC99_SOURCE)
val = trunc(val);
#else
val = val > 0 ? floor(val) : ceil(val);
#endif
if (val == 0 && mrb_float(x) < 0) {
return mrb_fixnum_value(-1);
}
}
else {
while (width--) {
val *= 2;
}
}
if (FIXABLE(val)) {
return mrb_fixnum_value(val);
}
return mrb_float_value(mrb, val);
}
static mrb_value
flo_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
mrb_get_args(mrb, "i", &width);
return flo_shift(mrb, x, -width);
}
static mrb_value
flo_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width;
mrb_get_args(mrb, "i", &width);
return flo_shift(mrb, x, width);
}
/* 15.2.8.3.18 */
/*
* call-seq:
@@ -738,17 +862,13 @@ fix_rev(mrb_state *mrb, mrb_value num)
return mrb_fixnum_value(~val);
}
static mrb_value
bit_coerce(mrb_state *mrb, mrb_value x)
{
while (!mrb_fixnum_p(x)) {
if (mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
}
x = mrb_to_int(mrb, x);
}
return x;
}
static mrb_value flo_and(mrb_state *mrb, mrb_value x);
static mrb_value flo_or(mrb_state *mrb, mrb_value x);
static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
#define bit_op(x,y,op1,op2) do {\
if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\
} while(0)
/* 15.2.8.3.9 */
/*
@@ -764,9 +884,7 @@ fix_and(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
y = bit_coerce(mrb, y);
return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y));
bit_op(x, y, and, &);
}
/* 15.2.8.3.10 */
@@ -783,9 +901,7 @@ fix_or(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
y = bit_coerce(mrb, y);
return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y));
bit_op(x, y, or, |);
}
/* 15.2.8.3.11 */
@@ -802,9 +918,7 @@ fix_xor(mrb_state *mrb, mrb_value x)
mrb_value y;
mrb_get_args(mrb, "o", &y);
y = bit_coerce(mrb, y);
return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y));
bit_op(x, y, or, ^);
}
#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
@@ -850,15 +964,6 @@ rshift(mrb_int val, mrb_int width)
return mrb_fixnum_value(val >> width);
}
static inline void
fix_shift_get_width(mrb_state *mrb, mrb_int *width)
{
mrb_value y;
mrb_get_args(mrb, "o", &y);
*width = mrb_fixnum(bit_coerce(mrb, y));
}
/* 15.2.8.3.12 */
/*
* call-seq:
@@ -872,8 +977,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
fix_shift_get_width(mrb, &width);
mrb_get_args(mrb, "i", &width);
if (width == 0) {
return x;
}
@@ -897,8 +1001,7 @@ fix_rshift(mrb_state *mrb, mrb_value x)
{
mrb_int width, val;
fix_shift_get_width(mrb, &width);
mrb_get_args(mrb, "i", &width);
if (width == 0) {
return x;
}
@@ -941,7 +1044,7 @@ fix_to_f(mrb_state *mrb, mrb_value num)
MRB_API mrb_value
mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
{
mrb_int z;
mrb_int z = 0;
if (!mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
@@ -1167,6 +1270,7 @@ mrb_init_numeric(mrb_state *mrb)
/* Integer Class */
integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
mrb_undef_class_method(mrb, integer, "new");
mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
@@ -1193,12 +1297,19 @@ mrb_init_numeric(mrb_state *mrb)
/* Float Class */
mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
mrb_undef_class_method(mrb, fl, "new");
mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
+8 -4
View File
@@ -8,6 +8,7 @@
#include <mruby/class.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
@@ -265,6 +266,7 @@ mrb_init_object(mrb_state *mrb)
struct RClass *f;
mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE);
mrb_undef_class_method(mrb, n, "new");
mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */
mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */
@@ -274,6 +276,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE());
mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class);
MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE);
mrb_undef_class_method(mrb, t, "new");
mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */
mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */
@@ -282,6 +285,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE());
mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class);
MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE);
mrb_undef_class_method(mrb, f, "new");
mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */
mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */
@@ -348,7 +352,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const
{
mrb_value v;
if (mrb_type(val) == type && type != MRB_TT_DATA) return val;
if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val;
v = convert_type(mrb, val, tname, method, FALSE);
if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value();
return v;
@@ -380,7 +384,7 @@ static const struct types {
/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */
/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */
/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */
{-1, 0}
{MRB_TT_MAXDEFINE, 0}
};
MRB_API void
@@ -390,7 +394,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
enum mrb_vtype xt;
xt = mrb_type(x);
if ((xt != t) || (xt == MRB_TT_DATA)) {
if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) {
while (type->type < MRB_TT_MAXDEFINE) {
if (type->type == t) {
const char *etype;
@@ -440,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
mrb_str_cat_lit(mrb, str, "#<");
mrb_str_cat_cstr(mrb, str, cname);
mrb_str_cat_lit(mrb, str, ":");
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj)));
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj)));
mrb_str_cat_lit(mrb, str, ">");
return str;
+18 -14
View File
@@ -140,7 +140,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
{
a->flags = b->flags;
a->body = b->body;
if (!MRB_PROC_CFUNC_P(a)) {
if (!MRB_PROC_CFUNC_P(a) && a->body.irep) {
a->body.irep->refcnt++;
}
a->target_class = b->target_class;
@@ -148,19 +148,22 @@ mrb_proc_copy(struct RProc *a, struct RProc *b)
}
static mrb_value
mrb_proc_initialize(mrb_state *mrb, mrb_value self)
mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class)
{
mrb_value blk;
mrb_value proc;
struct RProc *p;
mrb_get_args(mrb, "&", &blk);
if (mrb_nil_p(blk)) {
/* Calling Proc.new without a block is not implemented yet */
mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
}
else {
mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk));
}
return self;
p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class));
mrb_proc_copy(p, mrb_proc_ptr(blk));
proc = mrb_obj_value(p);
mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, blk);
return proc;
}
static mrb_value
@@ -188,18 +191,13 @@ mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self)
return (p->body.func)(mrb, self);
}
mrb_code*
mrb_proc_iseq(mrb_state *mrb, struct RProc *p)
{
return p->body.irep->iseq;
}
/* 15.2.17.4.2 */
static mrb_value
mrb_proc_arity(mrb_state *mrb, mrb_value self)
{
struct RProc *p = mrb_proc_ptr(self);
mrb_code *iseq = mrb_proc_iseq(mrb, p);
struct mrb_irep *irep;
mrb_code *iseq;
mrb_aspec aspec;
int ma, op, ra, pa, arity;
@@ -208,6 +206,12 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(-1);
}
irep = p->body.irep;
if (!irep) {
return mrb_fixnum_value(0);
}
iseq = irep->iseq;
/* arity is depend on OP_ENTER */
if (GET_OPCODE(*iseq) != OP_ENTER) {
return mrb_fixnum_value(0);
@@ -267,7 +271,7 @@ mrb_init_proc(mrb_state *mrb)
call_irep->iseq = call_iseq;
call_irep->ilen = 1;
mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE());
mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
+38 -29
View File
@@ -12,6 +12,17 @@
#define RANGE_CLASS (mrb_class_get(mrb, "Range"))
MRB_API struct RRange*
mrb_range_ptr(mrb_state *mrb, mrb_value v)
{
struct RRange *r = (struct RRange*)mrb_ptr(v);
if (r->edges == NULL) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range");
}
return r;
}
static void
range_check(mrb_state *mrb, mrb_value a, mrb_value b)
{
@@ -57,7 +68,7 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
mrb_value
mrb_range_beg(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
return r->edges->beg;
}
@@ -76,7 +87,7 @@ mrb_range_beg(mrb_state *mrb, mrb_value range)
mrb_value
mrb_range_end(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
return r->edges->end;
}
@@ -90,7 +101,7 @@ mrb_range_end(mrb_state *mrb, mrb_value range)
mrb_value
mrb_range_excl(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
return mrb_bool_value(r->excl);
}
@@ -98,7 +109,7 @@ mrb_range_excl(mrb_state *mrb, mrb_value range)
static void
range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end)
{
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_raw_ptr(range);
range_check(mrb, beg, end);
r->excl = exclude_end;
@@ -129,6 +140,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range)
exclusive = FALSE;
}
/* Ranges are immutable, so that they should be initialized only once. */
if (mrb_range_raw_ptr(range)->edges) {
mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice");
}
range_init(mrb, range, beg, end, exclusive);
return range;
}
@@ -161,8 +175,8 @@ mrb_range_eq(mrb_state *mrb, mrb_value range)
return mrb_false_value();
}
rr = mrb_range_ptr(range);
ro = mrb_range_ptr(obj);
rr = mrb_range_ptr(mrb, range);
ro = mrb_range_ptr(mrb, obj);
v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg);
v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end);
if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) {
@@ -219,7 +233,7 @@ mrb_value
mrb_range_include(mrb_state *mrb, mrb_value range)
{
mrb_value val;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
mrb_bool include_p;
@@ -227,31 +241,32 @@ mrb_range_include(mrb_state *mrb, mrb_value range)
beg = r->edges->beg;
end = r->edges->end;
include_p = r_le(mrb, beg, val) && /* beg <= val */
((r->excl && r_gt(mrb, end, val)) || /* end > val */
(r_ge(mrb, end, val))); /* end >= val */
include_p = r_le(mrb, beg, val) && /* beg <= val */
(r->excl ? r_gt(mrb, end, val) /* end > val */
: r_ge(mrb, end, val)); /* end >= val */
return mrb_bool_value(include_p);
}
static mrb_bool
range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
MRB_API mrb_int
mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
{
mrb_int beg, end;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r;
if (mrb_type(range) != MRB_TT_RANGE) return FALSE;
if (mrb_type(range) != MRB_TT_RANGE) return 0;
r = mrb_range_ptr(mrb, range);
beg = mrb_int(mrb, r->edges->beg);
end = mrb_int(mrb, r->edges->end);
if (beg < 0) {
beg += len;
if (beg < 0) return FALSE;
if (beg < 0) return 2;
}
if (trunc) {
if (beg > len) return FALSE;
if (beg > len) return 2;
if (end > len) end = len;
}
@@ -263,13 +278,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb
*begp = beg;
*lenp = len;
return TRUE;
}
MRB_API mrb_bool
mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len)
{
return range_beg_len(mrb, range, begp, lenp, len, TRUE);
return 1;
}
/* 15.2.14.4.12(x) */
@@ -284,7 +293,7 @@ static mrb_value
range_to_s(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
str = mrb_obj_as_string(mrb, r->edges->beg);
str2 = mrb_obj_as_string(mrb, r->edges->end);
@@ -309,7 +318,7 @@ static mrb_value
range_inspect(mrb_state *mrb, mrb_value range)
{
mrb_value str, str2;
struct RRange *r = mrb_range_ptr(range);
struct RRange *r = mrb_range_ptr(mrb, range);
str = mrb_inspect(mrb, r->edges->beg);
str2 = mrb_inspect(mrb, r->edges->end);
@@ -349,8 +358,8 @@ range_eql(mrb_state *mrb, mrb_value range)
}
if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value();
r = mrb_range_ptr(range);
o = mrb_range_ptr(obj);
r = mrb_range_ptr(mrb, range);
o = mrb_range_ptr(mrb, obj);
if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) ||
!mrb_eql(mrb, r->edges->end, o->edges->end) ||
(r->excl != o->excl)) {
@@ -373,7 +382,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
}
r = mrb_range_ptr(src);
r = mrb_range_ptr(mrb, src);
range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl);
return copy;
@@ -390,7 +399,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
if (mrb_fixnum_p(argv[i])) {
mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i])));
}
else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) {
else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) {
mrb_int const end = olen < beg + len ? olen : beg + len;
for (j = beg; j < end; ++j) {
mrb_ary_push(mrb, result, func(mrb, obj, j));
+4 -1
View File
@@ -159,7 +159,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
}
mrb_free(mrb, irep->reps);
mrb_free(mrb, irep->lv);
mrb_free(mrb, (void *)irep->filename);
if (irep->own_filename) {
mrb_free(mrb, (void *)irep->filename);
}
mrb_free(mrb, irep->lines);
mrb_debug_info_free(mrb, irep->debug_info);
mrb_free(mrb, irep);
@@ -261,6 +263,7 @@ mrb_add_irep(mrb_state *mrb)
irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep));
*irep = mrb_irep_zero;
irep->refcnt = 1;
irep->own_filename = FALSE;
return irep;
}
+313 -70
View File
@@ -118,9 +118,12 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
return mrb_obj_value(s);
}
static inline void
resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
static void
resize_capa(mrb_state *mrb, struct RString *s, size_t capacity)
{
#if SIZE_MAX > MRB_INT_MAX
mrb_assert(capacity < MRB_INT_MAX);
#endif
if (RSTR_EMBED_P(s)) {
if (RSTRING_EMBED_LEN_MAX < capacity) {
char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
@@ -129,12 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
RSTR_UNSET_EMBED_FLAG(s);
s->as.heap.ptr = tmp;
s->as.heap.len = len;
s->as.heap.aux.capa = capacity;
s->as.heap.aux.capa = (mrb_int)capacity;
}
}
else {
s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
s->as.heap.aux.capa = capacity;
s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
s->as.heap.aux.capa = (mrb_int)capacity;
}
}
@@ -151,22 +154,26 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
off = ptr - RSTR_PTR(s);
}
if (RSTR_EMBED_P(s))
capa = RSTRING_EMBED_LEN_MAX;
else
capa = s->as.heap.aux.capa;
capa = RSTR_CAPA(s);
if (capa <= RSTRING_EMBED_LEN_MAX)
capa = RSTRING_EMBED_LEN_MAX+1;
if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
total = RSTR_LEN(s)+len;
if (total >= MRB_INT_MAX) {
size_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
total = RSTR_LEN(s)+len;
if (capa <= total) {
while (total > capa) {
if (capa + 1 >= MRB_INT_MAX / 2) {
capa = (total + 4095) / 4096;
break;
if (capa <= MRB_INT_MAX / 2) {
capa *= 2;
}
capa = (capa + 1) * 2;
else {
capa = total;
}
}
if (capa < total || capa > MRB_INT_MAX) {
goto size_error;
}
resize_capa(mrb, s, capa);
}
@@ -361,7 +368,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
return 0;
}
else if (m == 1) {
const unsigned char *ys = memchr(y, *x, n);
const unsigned char *ys = (const unsigned char *)memchr(y, *x, n);
if (ys)
return ys - y;
@@ -416,7 +423,7 @@ byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
mrb_shared_string *shared;
orig = mrb_str_ptr(str);
if (RSTR_EMBED_P(orig)) {
if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) {
s = str_new(mrb, orig->as.ary+beg, len);
}
else {
@@ -501,7 +508,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
static void
check_frozen(mrb_state *mrb, struct RString *s)
{
if (RSTR_FROZEN_P(s)) {
if (MRB_FROZEN_P(s)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
}
}
@@ -512,6 +519,9 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
long len;
check_frozen(mrb, s1);
s1->flags &= ~MRB_STR_NO_UTF;
s1->flags |= s2->flags&MRB_STR_NO_UTF;
if (s1 == s2) return mrb_obj_value(s1);
len = RSTR_LEN(s2);
if (RSTR_SHARED_P(s1)) {
str_decref(mrb, s1->as.heap.aux.shared);
@@ -662,7 +672,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
s->as.heap.ptr = shared->ptr;
s->as.heap.aux.capa = shared->len;
RSTR_PTR(s)[s->as.heap.len] = '\0';
@@ -688,27 +698,25 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
}
if (RSTR_NOFREE_P(s)) {
char *p = s->as.heap.ptr;
mrb_int len = s->as.heap.len;
s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
if (p) {
memcpy(RSTR_PTR(s), p, s->as.heap.len);
}
RSTR_PTR(s)[s->as.heap.len] = '\0';
s->as.heap.aux.capa = s->as.heap.len;
RSTR_UNSET_NOFREE_FLAG(s);
if (len < RSTRING_EMBED_LEN_MAX) {
RSTR_SET_EMBED_FLAG(s);
RSTR_SET_EMBED_LEN(s, len);
}
else {
s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
s->as.heap.aux.capa = len;
}
if (p) {
memcpy(RSTR_PTR(s), p, len);
}
RSTR_PTR(s)[len] = '\0';
return;
}
}
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)
{
@@ -760,8 +768,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
if (RSTR_LEN(s2) == 0) {
return;
}
len = RSTR_LEN(s1) + RSTR_LEN(s2);
if (len < 0 || len >= MRB_INT_MAX) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
if (RSTRING_CAPA(self) < len) {
resize_capa(mrb, s1, len);
}
@@ -1079,22 +1093,25 @@ num_index:
return mrb_nil_value();
case MRB_TT_RANGE:
/* check if indx is Range */
{
mrb_int beg, len;
goto range_arg;
len = RSTRING_CHAR_LEN(str);
if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
return str_subseq(mrb, str, beg, len);
}
else {
return mrb_nil_value();
}
}
case MRB_TT_FLOAT:
default:
indx = mrb_Integer(mrb, indx);
if (mrb_nil_p(indx)) {
range_arg:
{
mrb_int beg, len;
len = RSTRING_CHAR_LEN(str);
switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) {
case 1:
return str_subseq(mrb, str, beg, len);
case 2:
return mrb_nil_value();
default:
break;
}
}
mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum");
}
idx = mrb_fixnum(indx);
@@ -1235,11 +1252,13 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
char *p, *pp;
mrb_int rslen;
mrb_int len;
mrb_int argc;
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
argc = mrb_get_args(mrb, "|S", &rs);
len = RSTR_LEN(s);
if (mrb_get_args(mrb, "|S", &rs) == 0) {
if (argc == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
if (RSTR_PTR(s)[len-1] == '\n') {
@@ -1530,22 +1549,12 @@ mrb_str_hash_m(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_str_include(mrb_state *mrb, mrb_value self)
{
mrb_int i;
mrb_value str2;
mrb_bool include_p;
mrb_get_args(mrb, "o", &str2);
if (mrb_fixnum_p(str2)) {
include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL);
}
else {
str2 = mrb_str_to_str(mrb, str2);
i = str_index(mrb, self, str2, 0);
include_p = (i != -1);
}
return mrb_bool_value(include_p);
mrb_get_args(mrb, "S", &str2);
if (str_index(mrb, self, str2, 0) < 0)
return mrb_bool_value(FALSE);
return mrb_bool_value(TRUE);
}
/* 15.2.10.5.22 */
@@ -1764,7 +1773,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
mrb_str_modify(mrb, mrb_str_ptr(str));
len = RSTRING_LEN(str);
buf = mrb_malloc(mrb, (size_t)len);
buf = (char*)mrb_malloc(mrb, (size_t)len);
p = buf;
e = buf + len;
@@ -2225,7 +2234,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
char *p = RSTR_PTR(ps);
if (!p || p[len] != '\0') {
if (RSTR_FROZEN_P(ps)) {
if (MRB_FROZEN_P(ps)) {
*ptr = str = mrb_str_dup(mrb, str);
ps = mrb_str_ptr(str);
}
@@ -2294,7 +2303,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
return 0.0;
}
d = strtod(p, &end);
d = mrb_float_read(p, &end);
if (p == end) {
if (badcheck) {
bad:
@@ -2332,7 +2341,7 @@ bad:
return 0.0;
}
d = strtod(p, &end);
d = mrb_float_read(p, &end);
if (badcheck) {
if (!end || p == end) goto bad;
while (*end && ISSPACE(*end)) end++;
@@ -2637,7 +2646,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
}
#endif
c = *p;
if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) {
if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) {
buf[0] = '\\'; buf[1] = c;
mrb_str_cat(mrb, result, buf, 2);
continue;
@@ -2723,8 +2732,8 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */
mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */
mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */
mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */
mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */
mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */
mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */
mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */
mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */
mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */
@@ -2754,6 +2763,240 @@ 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());
}
/*
* Source code for the "strtod" library procedure.
*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $
*/
#include <ctype.h>
#include <errno.h>
static const int maxExponent = 511; /* Largest possible base 10 exponent. Any
* exponent larger than this will already
* produce underflow or overflow, so there's
* no need to worry about additional digits.
*/
static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */
10., /* is 10^2^i. Used to convert decimal */
100., /* exponents into floating-point numbers. */
1.0e4,
1.0e8,
1.0e16,
1.0e32,
1.0e64,
1.0e128,
1.0e256
};
MRB_API double
mrb_float_read(const char *string, char **endPtr)
/* const char *string; A decimal ASCII floating-point number,
* optionally preceded by white space.
* Must have form "-I.FE-X", where I is the
* integer part of the mantissa, F is the
* fractional part of the mantissa, and X
* is the exponent. Either of the signs
* may be "+", "-", or omitted. Either I
* or F may be omitted, or both. The decimal
* point isn't necessary unless F is present.
* The "E" may actually be an "e". E and X
* may both be omitted (but not just one).
*/
/* char **endPtr; If non-NULL, store terminating character's
* address here. */
{
int sign, expSign = FALSE;
double fraction, dblExp;
const double *d;
register const char *p;
register int c;
int exp = 0; /* Exponent read from "EX" field. */
int fracExp = 0; /* Exponent that derives from the fractional
* part. Under normal circumstatnces, it is
* the negative of the number of digits in F.
* However, if I is very long, the last digits
* of I get dropped (otherwise a long I with a
* large negative exponent could cause an
* unnecessary overflow on I alone). In this
* case, fracExp is incremented one for each
* dropped digit. */
int mantSize; /* Number of digits in mantissa. */
int decPt; /* Number of mantissa digits BEFORE decimal
* point. */
const char *pExp; /* Temporarily holds location of exponent
* in string. */
/*
* Strip off leading blanks and check for a sign.
*/
p = string;
while (isspace(*p)) {
p += 1;
}
if (*p == '-') {
sign = TRUE;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
sign = FALSE;
}
/*
* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point.
*/
decPt = -1;
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
if (!isdigit(c)) {
if ((c != '.') || (decPt >= 0)) {
break;
}
decPt = mantSize;
}
p += 1;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
pExp = p;
p -= mantSize;
if (decPt < 0) {
decPt = mantSize;
} else {
mantSize -= 1; /* One of the digits was the point. */
}
if (mantSize > 18) {
if (decPt - 18 > 29999) {
fracExp = 29999;
} else {
fracExp = decPt - 18;
}
mantSize = 18;
} else {
fracExp = decPt - mantSize;
}
if (mantSize == 0) {
fraction = 0.0;
p = string;
goto done;
} else {
int frac1, frac2;
frac1 = 0;
for ( ; mantSize > 9; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac1 = 10*frac1 + (c - '0');
}
frac2 = 0;
for (; mantSize > 0; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac2 = 10*frac2 + (c - '0');
}
fraction = (1.0e9 * frac1) + frac2;
}
/*
* Skim off the exponent.
*/
p = pExp;
if ((*p == 'E') || (*p == 'e')) {
p += 1;
if (*p == '-') {
expSign = TRUE;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
expSign = FALSE;
}
while (isdigit(*p)) {
exp = exp * 10 + (*p - '0');
if (exp > 19999) {
exp = 19999;
}
p += 1;
}
}
if (expSign) {
exp = fracExp - exp;
} else {
exp = fracExp + exp;
}
/*
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
* fraction.
*/
if (exp < 0) {
expSign = TRUE;
exp = -exp;
} else {
expSign = FALSE;
}
if (exp > maxExponent) {
exp = maxExponent;
errno = ERANGE;
}
dblExp = 1.0;
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
if (exp & 01) {
dblExp *= *d;
}
}
if (expSign) {
fraction /= dblExp;
} else {
fraction *= dblExp;
}
done:
if (endPtr != NULL) {
*endPtr = (char *) p;
}
if (sign) {
return -fraction;
}
return fraction;
}
+3
View File
@@ -10,6 +10,7 @@
#include <mruby/khash.h>
#include <mruby/string.h>
#include <mruby/dump.h>
#include <mruby/class.h>
/* ------------------------------------------------------ */
typedef struct symbol_name {
@@ -481,6 +482,8 @@ mrb_init_symbol(mrb_state *mrb)
struct RClass *sym;
mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL);
mrb_undef_class_method(mrb, sym, "new");
mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */
mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
+5 -2
View File
@@ -44,7 +44,7 @@ iv_new(mrb_state *mrb)
{
iv_tbl *t;
t = mrb_malloc(mrb, sizeof(iv_tbl));
t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl));
t->size = 0;
t->rootseg = NULL;
t->last_len = 0;
@@ -102,7 +102,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
return;
}
seg = mrb_malloc(mrb, sizeof(segment));
seg = (segment*)mrb_malloc(mrb, sizeof(segment));
if (!seg) return;
seg->next = NULL;
seg->key[0] = sym;
@@ -489,6 +489,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t = obj->iv;
if (MRB_FROZEN_P(obj)) {
mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
}
if (!t) {
t = obj->iv = iv_new(mrb);
}
+176 -59
View File
@@ -40,6 +40,11 @@ void abort(void);
#define MRB_STACK_GROWTH 128
#endif
/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */
#ifndef MRB_FUNCALL_DEPTH_MAX
#define MRB_FUNCALL_DEPTH_MAX 512
#endif
/* Maximum stack depth. Should be set lower on memory constrained systems.
The value below allows about 60000 recursive calls in the simplest case. */
#ifndef MRB_STACK_MAX
@@ -54,6 +59,10 @@ The value below allows about 60000 recursive calls in the simplest case. */
#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
#define CALL_MAXARGS 127
void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
static inline void
stack_clear(mrb_value *from, size_t count)
{
@@ -130,9 +139,10 @@ static void
stack_extend_alloc(mrb_state *mrb, int room, int keep)
{
mrb_value *oldbase = mrb->c->stbase;
int size = mrb->c->stend - mrb->c->stbase;
int off = mrb->c->stack - mrb->c->stbase;
size_t size = mrb->c->stend - mrb->c->stbase;
size_t off = mrb->c->stack - mrb->c->stbase;
if (off > size) size = off;
#ifdef MRB_STACK_EXTEND_DOUBLING
if (room <= size)
size *= 2;
@@ -157,13 +167,16 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep)
to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
if (size > MRB_STACK_MAX) {
init_new_stack_space(mrb, room, keep);
mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
}
static inline void
stack_extend(mrb_state *mrb, int room, int keep)
{
if (room < keep) {
room = keep;
}
if (mrb->c->stack + room >= mrb->c->stend) {
stack_extend_alloc(mrb, room, keep);
}
@@ -234,6 +247,7 @@ cipush(mrb_state *mrb)
ci->pc = 0;
ci->err = 0;
ci->proc = 0;
ci->acc = 0;
return ci;
}
@@ -274,13 +288,17 @@ ecall(mrb_state *mrb, int i)
mrb_callinfo *ci;
mrb_value *self = mrb->c->stack;
struct RObject *exc;
int cioff;
mrb_value *nstk;
if (i<0) return;
p = mrb->c->ensure[i];
if (!p) return;
if (mrb->c->ci->eidx > i)
mrb->c->ci->eidx = i;
cioff = mrb->c->ci - mrb->c->cibase;
ci = cipush(mrb);
nstk = ci->stackent;
ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
ci->acc = CI_ACC_SKIP;
@@ -292,6 +310,8 @@ ecall(mrb_state *mrb, int i)
exc = mrb->exc; mrb->exc = 0;
mrb_run(mrb, p, *self);
mrb->c->ensure[i] = NULL;
ci->stackent = nstk;
mrb->c->ci = mrb->c->cibase + cioff;
if (!mrb->exc) mrb->exc = exc;
}
@@ -362,10 +382,17 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
c = mrb_class(mrb, self);
p = mrb_method_search_vm(mrb, &c, mid);
if (!p) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, missing);
if (!p) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
mrb_method_missing(mrb, mid, self, args);
}
undef = mid;
mid = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, mid);
n++; argc++;
argc++;
}
if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
ci = cipush(mrb);
ci->mid = mid;
@@ -381,8 +408,18 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->nregs = argc + 2;
stack_extend(mrb, ci->nregs, 0);
}
else if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
stack_extend(mrb, ci->nregs, 0);
mrb->c->stack[1] = args;
if (undef) {
mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef));
}
ci->argc = -1;
argc = 1;
}
else {
ci->nregs = p->body.irep->nregs + n;
ci->nregs = p->body.irep->nregs + argc;
stack_extend(mrb, ci->nregs, argc+2);
}
if (voff >= 0) {
@@ -395,7 +432,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
stack_copy(mrb->c->stack+2, argv, argc-1);
}
}
else if (argc > 0) {
else if (ci->argc > 0) {
stack_copy(mrb->c->stack+1, argv, argc);
}
mrb->c->stack[argc+1] = blk;
@@ -424,6 +461,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
mrb_value
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
ci->proc = p;
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
if (ci->argc < 0) {
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
}
else {
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
}
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
ci->acc = 0;
return self;
}
/* 15.3.1.3.4 */
/* 15.3.1.3.44 */
/*
@@ -465,7 +529,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
ci = mrb->c->ci;
ci->mid = name;
ci->target_class = c;
ci->proc = p;
regs = mrb->c->stack+1;
/* remove first symbol from arguments */
if (ci->argc >= 0) {
@@ -478,26 +541,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
mrb_ary_shift(mrb, regs[0]);
}
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
if (ci->argc < 0) {
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
}
else {
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
}
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
ci->acc = 0;
return self;
return mrb_exec_irep(mrb, self, p);
}
static mrb_value
@@ -646,11 +690,13 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
if (MRB_PROC_CFUNC_P(p)) {
val = p->body.func(mrb, self);
mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
else {
int cioff = mrb->c->ci - mrb->c->cibase;
val = mrb_run(mrb, p, self);
mrb->c->ci = mrb->c->cibase + cioff;
}
cipop(mrb);
return val;
}
@@ -697,15 +743,22 @@ argnum_error(mrb_state *mrb, mrb_int num)
{
mrb_value exc;
mrb_value str;
mrb_int argc = mrb->c->ci->argc;
if (argc < 0) {
mrb_value args = mrb->c->stack[1];
if (mrb_array_p(args)) {
argc = RARRAY_LEN(args);
}
}
if (mrb->c->ci->mid) {
str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
mrb_sym2str(mrb, mrb->c->ci->mid),
mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
mrb_fixnum_value(argc), mrb_fixnum_value(num));
}
else {
str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
mrb_fixnum_value(argc), mrb_fixnum_value(num));
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
mrb_exc_set(mrb, exc);
@@ -749,10 +802,6 @@ argnum_error(mrb_state *mrb, mrb_int num)
#endif
#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_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
@@ -831,7 +880,15 @@ RETRY_TRY_BLOCK:
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
#ifdef MRB_WORD_BOXING
mrb_value val = pool[GETARG_Bx(i)];
if (mrb_float_p(val)) {
val = mrb_float_value(mrb, mrb_float(val));
}
regs[GETARG_A(i)] = val;
#else
regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
#endif
NEXT;
}
@@ -1105,12 +1162,14 @@ RETRY_TRY_BLOCK:
}
if (GET_OPCODE(i) != OP_SENDB) {
SET_NIL_VALUE(regs[bidx]);
bidx = 0;
}
else {
mrb_value blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
}
bidx = 1;
}
c = mrb_class(mrb, recv);
m = mrb_method_search_vm(mrb, &c, mid);
@@ -1131,12 +1190,17 @@ RETRY_TRY_BLOCK:
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
if (n == CALL_MAXARGS-1) {
regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
n++;
}
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
}
else {
value_move(regs+a+2, regs+a+1, ++n);
value_move(regs+a+2, regs+a+1, n+bidx);
regs[a+1] = sym;
n++;
}
}
@@ -1263,7 +1327,9 @@ RETRY_TRY_BLOCK:
else {
stack_extend(mrb, irep->nregs, ci->argc+2);
}
regs[0] = m->env->stack[0];
if(m->env) {
regs[0] = m->env->stack[0];
}
pc = irep->iseq;
JUMP;
}
@@ -1279,7 +1345,7 @@ RETRY_TRY_BLOCK:
int a = GETARG_A(i);
int n = GETARG_C(i);
if (mid == 0) {
if (mid == 0 || !mrb->c->ci->target_class) {
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
@@ -1290,8 +1356,24 @@ RETRY_TRY_BLOCK:
c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
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-1) {
regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
n++;
}
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
}
@@ -1306,11 +1388,22 @@ RETRY_TRY_BLOCK:
ci->mid = mid;
ci->proc = m;
ci->stackent = mrb->c->stack;
if (n == CALL_MAXARGS) {
ci->argc = -1;
}
else {
ci->argc = n;
{
int bidx;
mrb_value blk;
if (n == CALL_MAXARGS) {
ci->argc = -1;
bidx = a+2;
}
else {
ci->argc = n;
bidx = a+n+1;
}
blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
}
}
ci->target_class = c;
ci->pc = pc + 1;
@@ -1578,7 +1671,7 @@ RETRY_TRY_BLOCK:
switch (GETARG_B(i)) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
if (proc->env && !MRB_PROC_STRICT_P(proc)) {
if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) {
struct REnv *e = top_env(mrb, proc);
if (!MRB_ENV_STACK_SHARED_P(e)) {
@@ -1647,10 +1740,11 @@ RETRY_TRY_BLOCK:
mrb->jmp = prev_jmp;
return v;
}
cipop(mrb);
ci = mrb->c->ci;
acc = ci->acc;
mrb->c->stack = ci->stackent;
if (acc == CI_ACC_SKIP) {
cipop(mrb);
if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
mrb->jmp = prev_jmp;
return v;
}
@@ -1681,9 +1775,20 @@ 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");
m = mrb_method_search_vm(mrb, &c, missing);
if (!m) {
mrb_value args;
mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
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);
}
@@ -2134,8 +2239,8 @@ RETRY_TRY_BLOCK:
CASE(OP_ARYCAT) {
/* A B mrb_ary_concat(R(A),R(B)) */
mrb_ary_concat(mrb, regs[GETARG_A(i)],
mrb_ary_splat(mrb, regs[GETARG_B(i)]));
mrb_value splat = mrb_ary_splat(mrb, regs[GETARG_B(i)]);
mrb_ary_concat(mrb, regs[GETARG_A(i)], splat);
ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2261,7 +2366,7 @@ RETRY_TRY_BLOCK:
CASE(OP_CLASS) {
/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
struct RClass *c = 0;
struct RClass *c = 0, *baseclass;
int a = GETARG_A(i);
mrb_value base, super;
mrb_sym id = syms[GETARG_B(i)];
@@ -2269,7 +2374,10 @@ RETRY_TRY_BLOCK:
base = regs[a];
super = regs[a+1];
if (mrb_nil_p(base)) {
base = mrb_obj_value(mrb->c->ci->target_class);
baseclass = mrb->c->ci->proc->target_class;
if (!baseclass) baseclass = mrb->c->ci->target_class;
base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_class(mrb, base, super, id);
regs[a] = mrb_obj_value(c);
@@ -2279,14 +2387,17 @@ RETRY_TRY_BLOCK:
CASE(OP_MODULE) {
/* A B R(A) := newmodule(R(A),Syms(B)) */
struct RClass *c = 0;
struct RClass *c = 0, *baseclass;
int a = GETARG_A(i);
mrb_value base;
mrb_sym id = syms[GETARG_B(i)];
base = regs[a];
if (mrb_nil_p(base)) {
base = mrb_obj_value(mrb->c->ci->target_class);
baseclass = mrb->c->ci->proc->target_class;
if (!baseclass) baseclass = mrb->c->ci->target_class;
base = mrb_obj_value(baseclass);
}
c = mrb_vm_define_module(mrb, base, id);
regs[a] = mrb_obj_value(c);
@@ -2373,7 +2484,8 @@ RETRY_TRY_BLOCK:
CASE(OP_RANGE) {
/* A B C R(A) := range_new(R(B),R(B+1),C) */
int b = GETARG_B(i);
regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
regs[GETARG_A(i)] = val;
ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2439,7 +2551,12 @@ RETRY_TRY_BLOCK:
MRB_API mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
if (mrb->c->ci->argc < 0) {
return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */
}
else {
return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
}
MRB_API mrb_value
+4 -4
View File
@@ -5,17 +5,17 @@ MRuby.each_target do
file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t|
open(t.name, 'w') do |f|
f.puts "MRUBY_CFLAGS = #{cc.all_flags.gsub('"', '\\"')}"
f.puts "MRUBY_CFLAGS = #{cc.all_flags}"
gem_flags = gems.map { |g| g.linker.flags }
gem_library_paths = gems.map { |g| g.linker.library_paths }
f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags).gsub('"', '\\"')} #{linker.option_library_path % "#{build_dir}/lib"}"
f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags)} #{linker.option_library_path % "#{build_dir}/lib"}"
gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries }
f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ').gsub('"', '\\"')}"
f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ')}"
gem_libraries = gems.map { |g| g.linker.libraries }
f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries).gsub('"', '\\"')}"
f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}"
end
end
task :all => "#{build_dir}/lib/libmruby.flags.mak"
+20
View File
@@ -1,6 +1,7 @@
require 'pathname'
require 'forwardable'
require 'tsort'
require 'shellwords'
module MRuby
module Gem
@@ -89,7 +90,9 @@ module MRuby
build.libmruby << @objs
instance_eval(&@build_config_initializer) if @build_config_initializer
end
def setup_compilers
compilers.each do |compiler|
compiler.define_rules build_dir, "#{dir}"
compiler.defines << %Q[MRBGEM_#{funcname.upcase}_VERSION=#{version}]
@@ -126,6 +129,21 @@ module MRuby
"#{build_dir}/gem_test.c"
end
def search_package(name, version_query=nil)
package_query = name
package_query += " #{version_query}" if version_query
_pp "PKG-CONFIG", package_query
escaped_package_query = Shellwords.escape(package_query)
if system("pkg-config --exists #{escaped_package_query}")
cc.flags += [`pkg-config --cflags #{escaped_package_query}`.strip]
cxx.flags += [`pkg-config --cflags #{escaped_package_query}`.strip]
linker.flags_before_libraries += [`pkg-config --libs #{escaped_package_query}`.strip]
true
else
false
end
end
def funcname
@funcname ||= @name.gsub('-', '_')
end
@@ -403,6 +421,8 @@ module MRuby
@ary = tsort_dependencies gem_table.keys, gem_table, true
each(&:setup_compilers)
each do |g|
import_include_paths(g)
end
+5
View File
@@ -120,6 +120,7 @@ module MRuby
def enable_cxx_abi
return if @cxx_exception_disabled or @cxx_abi_enabled
compilers.each { |c| c.defines += %w(MRB_ENABLE_CXX_EXCEPTION) }
compilers.each { |c| c.flags << c.cxx_compile_flag }
linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
@cxx_abi_enabled = true
end
@@ -135,9 +136,13 @@ module MRuby
#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#ifndef MRB_ENABLE_CXX_EXCEPTION
extern "C" {
#endif
#include "#{src}"
#ifndef MRB_ENABLE_CXX_EXCEPTION
}
#endif
#{src == "#{MRUBY_ROOT}/src/error.c"? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''}
EOS
+1
View File
@@ -41,6 +41,7 @@ module MRuby
class Command::Compiler < Command
attr_accessor :flags, :include_paths, :defines, :source_exts
attr_accessor :compile_options, :option_define, :option_include_path, :out_ext
attr_accessor :cxx_compile_flag
def initialize(build, source_exts=[])
super(build)
+41 -10
View File
@@ -203,23 +203,53 @@ Set ANDROID_PLATFORM environment variable or set :platform parameter
def cflags
flags = []
flags += %W(-D__android__ --sysroot="#{sysroot}")
flags += %W(-MMD -MP)
flags += %W(-D__android__ -DANDROID --sysroot="#{sysroot}")
case toolchain
when :gcc
flags += %W(-mandroid)
case arch
when /armeabi-v7a/ then flags += %W(-march=armv7-a)
when /armeabi/ then flags += %W(-march=armv5te)
when /arm64-v8a/ then flags += %W(-march=armv8-a)
when /armeabi-v7a/ then flags += %W(-march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -fpic)
when /armeabi/ then flags += %W(-march=armv5te -mtune=xscale -msoft-float -fpic)
when /arm64-v8a/ then flags += %W(-march=armv8-a -fpic)
when /x86_64/ then flags += %W(-march=x86-64)
when /x86/ then flags += %W(-march=i686)
when /mips64/ then flags += %W(-march=mips64)
when /mips/ then flags += %W(-march=mips32)
when /mips64/ then flags += %W(-march=mips64r6 -fmessage-length=0 -fpic)
when /mips/ then flags += %W(-march=mips32 -fmessage-length=0 -fpic)
end
when :clang
flags += %W(-gcc-toolchain "#{gcc_toolchain_path.to_s}")
case arch
when /armeabi-v7a/ then flags += %W(-target armv7-none-linux-androideabi)
when /armeabi-v7a/ then flags += %W(-target armv7-none-linux-androideabi -fpic)
when /armeabi/ then flags += %W(-target armv5te-none-linux-androideabi -fpic)
when /arm64-v8a/ then flags += %W(-target aarch64-none-linux-android -fpic)
when /x86_64/ then flags += %W(-target x86_64-none-linux-android -fPIC)
when /x86/ then flags += %W(-target i686-none-linux-android -fPIC)
when /mips64/ then flags += %W(-target mips64el-none-linux-android -fmessage-length=0 -fpic)
when /mips/ then flags += %W(-target mipsel-none-linux-android -fmessage-length=0 -fpic)
end
flags += %W(-Wno-invalid-command-line-argument -Wno-unused-command-line-argument)
end
flags += %W(-ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes)
flags
end
def ldflags
flags = []
flags += %W(--sysroot="#{sysroot}")
flags
end
def ldflags_before_libraries
flags = []
case toolchain
when :clang
flags += %W(-gcc-toolchain "#{gcc_toolchain_path.to_s}")
case arch
when /armeabi-v7a/ then flags += %W(-target armv7-none-linux-androideabi -Wl,--fix-cortex-a8)
when /armeabi/ then flags += %W(-target armv5te-none-linux-androideabi)
when /arm64-v8a/ then flags += %W(-target aarch64-none-linux-android)
when /x86_64/ then flags += %W(-target x86_64-none-linux-android)
@@ -228,10 +258,10 @@ Set ANDROID_PLATFORM environment variable or set :platform parameter
when /mips/ then flags += %W(-target mipsel-none-linux-android)
end
end
flags += %W(-no-canonical-prefixes)
flags
end
end
MRuby::Toolchain.new(:android) do |conf, params|
@@ -246,5 +276,6 @@ MRuby::Toolchain.new(:android) do |conf, params|
conf.archiver.command = android.ar
conf.linker.command = android.cc
conf.linker.flags = []
conf.linker.flags = android.ldflags
conf.linker.flags_before_libraries = android.ldflags_before_libraries
end
+2
View File
@@ -6,6 +6,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params|
cc.option_include_path = '-I%s'
cc.option_define = '-D%s'
cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
cc.cxx_compile_flag = '-x c++ -std=c++03'
end
[conf.cxx].each do |cxx|
@@ -15,6 +16,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params|
cxx.option_include_path = '-I%s'
cxx.option_define = '-D%s'
cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}'
cxx.cxx_compile_flag = '-x c++ -std=c++03'
end
conf.linker do |linker|
+2
View File
@@ -7,6 +7,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params|
cc.option_include_path = '/I%s'
cc.option_define = '/D%s'
cc.compile_options = "%{flags} /Fo%{outfile} %{infile}"
cc.cxx_compile_flag = '/TP'
end
conf.cxx do |cxx|
@@ -16,6 +17,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params|
cxx.option_include_path = '/I%s'
cxx.option_define = '/D%s'
cxx.compile_options = "%{flags} /Fo%{outfile} %{infile}"
cxx.cxx_compile_flag = '/TP'
end
conf.linker do |linker|
+4 -3
View File
@@ -44,7 +44,8 @@ def assert(str = 'Assertion failed', iso = '')
begin
$mrbtest_assert = []
$mrbtest_assert_idx = 0
if(!yield || $mrbtest_assert.size > 0)
yield
if($mrbtest_assert.size > 0)
$asserts.push(assertion_string('Fail: ', str, iso, nil))
$ko_test += 1
t_print('F')
@@ -213,7 +214,7 @@ def report()
t_print("\n")
$asserts.each do |msg|
puts msg
t_print "#{msg}\n"
end
$total_test = $ok_test+$ko_test+$kill_test
@@ -232,7 +233,7 @@ end
##
# Performs fuzzy check for equality on methods returning floats
def check_float(a, b)
tolerance = 1e-12
tolerance = Mrbtest::FLOAT_TOLERANCE
a = a.to_f
b = b.to_f
if a.finite? and b.finite?

Some files were not shown because too many files have changed in this diff Show More