mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge branch 'master' into android.rake-ndk-clang
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -34,3 +34,4 @@ Original Authors "mruby developers" are:
|
||||
Yuichi Osawa
|
||||
Terence Lee
|
||||
Zachary Scott
|
||||
Tomasz Dąbrowski
|
||||
|
||||
@@ -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
@@ -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'
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
*
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
##
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user