summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/mrbconf.h206
-rw-r--r--include/mruby.h1603
-rw-r--r--include/mruby/array.h321
-rw-r--r--include/mruby/boxing_nan.h201
-rw-r--r--include/mruby/boxing_no.h35
-rw-r--r--include/mruby/boxing_word.h289
-rw-r--r--include/mruby/class.h83
-rw-r--r--include/mruby/common.h92
-rw-r--r--include/mruby/compile.h123
-rw-r--r--include/mruby/data.h50
-rw-r--r--include/mruby/debug.h37
-rw-r--r--include/mruby/dump.h85
-rw-r--r--include/mruby/endian.h44
-rw-r--r--include/mruby/error.h141
-rw-r--r--include/mruby/gc.h90
-rw-r--r--include/mruby/hash.h240
-rw-r--r--include/mruby/irep.h139
-rw-r--r--include/mruby/istruct.h50
-rw-r--r--include/mruby/khash.h66
-rw-r--r--include/mruby/numeric.h177
-rw-r--r--include/mruby/object.h47
-rw-r--r--include/mruby/opcode.h199
-rw-r--r--include/mruby/ops.h118
-rw-r--r--include/mruby/presym.h40
-rw-r--r--include/mruby/presym/disable.h70
-rw-r--r--include/mruby/presym/enable.h37
-rw-r--r--include/mruby/presym/scanning.h73
-rw-r--r--include/mruby/proc.h196
-rw-r--r--include/mruby/range.h69
-rw-r--r--include/mruby/re.h12
-rw-r--r--include/mruby/string.h454
-rw-r--r--include/mruby/throw.h66
-rw-r--r--include/mruby/value.h391
-rw-r--r--include/mruby/variable.h140
-rw-r--r--include/mruby/version.h139
35 files changed, 4867 insertions, 1256 deletions
diff --git a/include/mrbconf.h b/include/mrbconf.h
index ac33ff0bf..e11a55e8c 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -7,36 +7,125 @@
#ifndef MRUBYCONF_H
#define MRUBYCONF_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
+/* add -DMRB_USE_FLOAT32 to use float instead of double for floating-point numbers */
+//#define MRB_USE_FLOAT32
-/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
-//#define MRB_INT16
+/* exclude floating-point numbers */
+//#define MRB_NO_FLOAT
-/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */
-//#define MRB_INT64
+/* obsolete configuration */
+#if defined(MRB_USE_FLOAT)
+# define MRB_USE_FLOAT32
+#endif
-/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT */
-//#define MRB_NAN_BOXING
+/* obsolete configuration */
+#if defined(MRB_WITHOUT_FLOAT)
+# define MRB_NO_FLOAT
+#endif
-/* define on big endian machines; used by MRB_NAN_BOXING */
-//#define MRB_ENDIAN_BIG
+#if defined(MRB_USE_FLOAT32) && defined(MRB_NO_FLOAT)
+#error Cannot define MRB_USE_FLOAT32 and MRB_NO_FLOAT at the same time
+#endif
+
+/* add -DMRB_NO_METHOD_CACHE to disable method cache to save memory */
+//#define MRB_NO_METHOD_CACHE
+/* size of the method cache (need to be the power of 2) */
+//#define MRB_METHOD_CACHE_SIZE (1<<8)
+
+/* add -DMRB_USE_METHOD_T_STRUCT on machines that use higher bits of function pointers */
+/* no MRB_USE_METHOD_T_STRUCT requires highest 2 bits of function pointers to be zero */
+#ifndef MRB_USE_METHOD_T_STRUCT
+ // can't use highest 2 bits of function pointers at least on 32bit
+ // Windows and 32bit Linux.
+# ifdef MRB_32BIT
+# define MRB_USE_METHOD_T_STRUCT
+# endif
+#endif
+
+/* define on big endian machines; used by MRB_NAN_BOXING, etc. */
+#ifndef MRB_ENDIAN_BIG
+# if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+# define MRB_ENDIAN_BIG
+# endif
+#endif
+
+/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT32 and MRB_NO_FLOAT */
+//#define MRB_NAN_BOXING
/* represent mrb_value as a word (natural unit of data for the processor) */
//#define MRB_WORD_BOXING
+/* represent mrb_value as a struct; occupies 2 words */
+//#define MRB_NO_BOXING
+
+/* if no specific boxing type is chosen */
+#if !defined(MRB_NAN_BOXING) && !defined(MRB_WORD_BOXING) && !defined(MRB_NO_BOXING)
+# define MRB_WORD_BOXING
+#endif
+
+/* if defined mruby allocates Float objects in the heap to keep full precision if needed */
+//#define MRB_WORDBOX_NO_FLOAT_TRUNCATE
+
+/* add -DMRB_INT32 to use 32bit integer for mrb_int; conflict with MRB_INT64;
+ Default for 32-bit CPU mode. */
+//#define MRB_INT32
+
+/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT32;
+ Default for 64-bit CPU mode (unless using MRB_NAN_BOXING). */
+//#define MRB_INT64
+
+/* if no specific integer type is chosen */
+#if !defined(MRB_INT32) && !defined(MRB_INT64)
+# if defined(MRB_64BIT) && !defined(MRB_NAN_BOXING)
+/* Use 64bit integers on 64bit architecture (without MRB_NAN_BOXING) */
+# define MRB_INT64
+# else
+/* Otherwise use 32bit integers */
+# define MRB_INT32
+# endif
+#endif
+
+/* call malloc_trim(0) from mrb_full_gc() */
+//#define MRB_USE_MALLOC_TRIM
+
+/* string class to handle UTF-8 encoding */
+//#define MRB_UTF8_STRING
+
/* argv max size in mrb_funcall */
//#define MRB_FUNCALL_ARGC_MAX 16
/* number of object per heap page */
//#define MRB_HEAP_PAGE_SIZE 1024
-/* use segmented list for IV table */
-//#define MRB_USE_IV_SEGLIST
+/* define if your platform does not support etext, edata */
+//#define MRB_NO_DEFAULT_RO_DATA_P
-/* initial size for IV khash; ignored when MRB_USE_IV_SEGLIST is set */
-//#define MRB_IVHASH_INIT_SIZE 8
+/* define if your platform supports etext, edata */
+//#define MRB_USE_RO_DATA_P_ETEXT
+/* use MRB_USE_ETEXT_RO_DATA_P by default on Linux */
+#if (defined(__linux__) && !defined(__KERNEL__))
+#define MRB_USE_ETEXT_RO_DATA_P
+#endif
+
+/* you can provide and use mrb_ro_data_p() for your platform.
+ prototype is `mrb_bool mrb_ro_data_p(const char *ptr)` */
+//#define MRB_USE_CUSTOM_RO_DATA_P
/* turn off generational GC by default */
//#define MRB_GC_TURN_OFF_GENERATIONAL
@@ -50,9 +139,6 @@
/* page size of memory pool */
//#define POOL_PAGE_SIZE 16000
-/* initial minimum size for string buffer */
-//#define MRB_STR_BUF_MIN_SIZE 128
-
/* arena size */
//#define MRB_GC_ARENA_SIZE 100
@@ -65,32 +151,82 @@
/* fixed size state atexit stack */
//#define MRB_FIXED_STATE_ATEXIT_STACK
-/* -DDISABLE_XXXX to drop following features */
-//#define DISABLE_STDIO /* use of stdio */
+/* -DMRB_NO_XXXX to drop following features */
+//#define MRB_NO_STDIO /* use of stdio */
-/* -DENABLE_XXXX to enable following features */
-//#define ENABLE_DEBUG /* hooks for debugger */
-
-/* end of configuration */
+/* -DMRB_USE_XXXX to enable following features */
+//#define MRB_USE_DEBUG_HOOK /* hooks for debugger */
+//#define MRB_USE_ALL_SYMBOLS /* Symbol.all_symbols */
-/* define ENABLE_XXXX from DISABLE_XXX */
-#ifndef DISABLE_STDIO
-#define ENABLE_STDIO
+/* obsolete configurations */
+#ifdef MRB_METHOD_T_STRUCT
+# define MRB_USE_METHOD_T_STRUCT
#endif
-#ifndef ENABLE_DEBUG
-#define DISABLE_DEBUG
+#if defined(DISABLE_STDIO) || defined(MRB_DISABLE_STDIO)
+# define MRB_NO_STDIO
#endif
-
-#ifdef ENABLE_STDIO
-# include <stdio.h>
+#ifdef MRB_DISABLE_DIRECT_THREADING
+# define MRB_NO_DIRECT_THREADING
+#endif
+#if defined(ENABLE_DEBUG) || defined(MRB_ENABLE_DEBUG_HOOK)
+# define MRB_USE_DEBUG_HOOK
+#endif
+#ifdef MRB_ENABLE_ALL_SYMBOLS
+# define MRB_USE_ALL_SYMBOLS
+#endif
+#ifdef MRB_ENABLE_CXX_ABI
+# define MRB_USE_CXX_ABI
#endif
+#ifdef MRB_ENABLE_CXX_EXCEPTION
+# define MRB_USE_CXX_EXCEPTION
+#endif
+
+/* end of configuration */
-#ifndef FALSE
-# define FALSE 0
+#ifndef MRB_NO_STDIO
+# include <stdio.h>
#endif
-#ifndef TRUE
-# define TRUE 1
+/*
+** mruby tuning profiles
+**/
+
+/* A profile for micro controllers */
+#if defined(MRB_CONSTRAINED_BASELINE_PROFILE)
+# ifndef MRB_NO_METHOD_CACHE
+# define MRB_NO_METHOD_CACHE
+# endif
+
+# ifndef KHASH_DEFAULT_SIZE
+# define KHASH_DEFAULT_SIZE 16
+# endif
+
+# ifndef MRB_HEAP_PAGE_SIZE
+# define MRB_HEAP_PAGE_SIZE 256
+# endif
+
+/* A profile for default mruby */
+#elif defined(MRB_BASELINE_PROFILE)
+
+/* A profile for desktop computers or workstations; rich memory! */
+#elif defined(MRB_MAIN_PROFILE)
+# ifndef MRB_METHOD_CACHE_SIZE
+# define MRB_METHOD_CACHE_SIZE (1<<10)
+# endif
+
+# ifndef MRB_HEAP_PAGE_SIZE
+# define MRB_HEAP_PAGE_SIZE 4096
+# endif
+
+/* A profile for server; mruby vm is long life */
+#elif defined(MRB_HIGH_PROFILE)
+# ifndef MRB_METHOD_CACHE_SIZE
+# define MRB_METHOD_CACHE_SIZE (1<<12)
+# endif
+
+# ifndef MRB_HEAP_PAGE_SIZE
+# define MRB_HEAP_PAGE_SIZE 4096
+# endif
#endif
#endif /* MRUBYCONF_H */
diff --git a/include/mruby.h b/include/mruby.h
index c4466de4c..f80971543 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
-** Copyright (c) mruby developers 2010-2014
+** Copyright (c) mruby developers 2010-2021
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
@@ -22,59 +22,154 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
-** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+** [ MIT license: https://www.opensource.org/licenses/mit-license.php ]
*/
+/**
+ * @file mruby.h
+ */
+
#ifndef MRUBY_H
#define MRUBY_H
-#if defined(__cplusplus)
-extern "C" {
+#ifdef __cplusplus
+#define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+#define __STDC_FORMAT_MACROS
#endif
+#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
+#ifdef __cplusplus
+#ifndef UINTPTR_MAX
+#error Must be placed `#include <mruby.h>` before `#include <stdint.h>`
+#endif
+#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 _MSC_VER
+# define __func__ __FUNCTION__
+#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 (defined __cplusplus && __cplusplus >= 201103L) || \
+ (defined _MSC_VER) || \
+ (defined __GXX_EXPERIMENTAL_CXX0X__) /* for old G++/Clang++ */
+# define mrb_static_assert(exp, str) static_assert(exp, str)
+#elif defined __STDC_VERSION__ && \
+ ((__STDC_VERSION__ >= 201112L) || \
+ (defined __GNUC__ && __GNUC__ * 100 + __GNUC_MINOR__ >= 406))
+# define mrb_static_assert(exp, str) _Static_assert(exp, str)
+#else
+# /* alternative implementation of static_assert() */
+# define _mrb_static_assert_cat0(a, b) a##b
+# define _mrb_static_assert_cat(a, b) _mrb_static_assert_cat0(a, b)
+# ifdef __COUNTER__
+# define _mrb_static_assert_id(prefix) _mrb_static_assert_cat(prefix, __COUNTER__)
+# else
+# define _mrb_static_assert_id(prefix) _mrb_static_assert_cat(prefix, __LINE__)
+# endif
+# define mrb_static_assert(exp, str) \
+ struct _mrb_static_assert_id(_mrb_static_assert_) { char x[(exp) ? 1 : -1]; }
+#endif
+#define mrb_static_assert1(exp) mrb_static_assert(exp, #exp)
+
#include "mrbconf.h"
-#include "mruby/value.h"
-#include "mruby/version.h"
-typedef uint32_t mrb_code;
+#include <mruby/common.h>
+#include <mruby/value.h>
+#include <mruby/gc.h>
+#include <mruby/version.h>
+
+#ifndef MRB_NO_FLOAT
+#include <math.h>
+#include <float.h>
+#ifndef FLT_EPSILON
+#define FLT_EPSILON (1.19209290e-07f)
+#endif
+#ifndef DBL_EPSILON
+#define DBL_EPSILON ((double)2.22044604925031308085e-16L)
+#endif
+#ifndef LDBL_EPSILON
+#define LDBL_EPSILON (1.08420217248550443401e-19L)
+#endif
+
+#ifdef MRB_USE_FLOAT32
+#define MRB_FLOAT_EPSILON FLT_EPSILON
+#else
+#define MRB_FLOAT_EPSILON DBL_EPSILON
+#endif
+#endif
+
+/**
+ * MRuby C API entry point
+ */
+MRB_BEGIN_DECL
+
+typedef uint8_t mrb_code;
+
+/**
+ * \class mrb_aspec
+ *
+ * Specifies the number of arguments a function takes
+ *
+ * Example: `MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)` for a method that expects 2..3 arguments
+ */
typedef uint32_t mrb_aspec;
struct mrb_irep;
struct mrb_state;
+/**
+ * Function pointer type of custom allocator used in @see mrb_open_allocf.
+ *
+ * The function pointing it must behave similarly as realloc except:
+ * - If ptr is NULL it must allocate new space.
+ * - If s is NULL, ptr must be freed.
+ *
+ * See @see mrb_default_allocf for the default implementation.
+ */
typedef void* (*mrb_allocf) (struct mrb_state *mrb, void*, size_t, void *ud);
-#ifndef MRB_GC_ARENA_SIZE
-#define MRB_GC_ARENA_SIZE 100
-#endif
-
#ifndef MRB_FIXED_STATE_ATEXIT_STACK_SIZE
#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5
#endif
typedef struct {
+ uint8_t n:4; /* (15=*) c=n|nk<<4 */
+ uint8_t nk:4; /* (15=*) */
+ uint8_t cci; /* called from C function */
mrb_sym mid;
- struct RProc *proc;
- mrb_value *stackent;
- int nregs;
- int ridx;
- int eidx;
- struct REnv *env;
- mrb_code *pc; /* return address */
- mrb_code *err; /* error position */
- int argc;
- int acc;
- struct RClass *target_class;
+ const struct RProc *proc;
+ mrb_value *stack;
+ const mrb_code *pc; /* current address on iseq of this proc */
+ union {
+ struct REnv *env;
+ struct RClass *target_class;
+ } u;
} mrb_callinfo;
enum mrb_fiber_state {
MRB_FIBER_CREATED = 0,
MRB_FIBER_RUNNING,
- MRB_FIBER_RESUMING,
+ MRB_FIBER_RESUMED,
MRB_FIBER_SUSPENDED,
MRB_FIBER_TRANSFERRED,
MRB_FIBER_TERMINATED,
@@ -83,26 +178,54 @@ enum mrb_fiber_state {
struct mrb_context {
struct mrb_context *prev;
- mrb_value *stack; /* stack of virtual machine */
- mrb_value *stbase, *stend;
+ mrb_value *stbase, *stend; /* stack of virtual machine */
mrb_callinfo *ci;
mrb_callinfo *cibase, *ciend;
- mrb_code **rescue; /* exception handler stack */
- int rsize;
- struct RProc **ensure; /* ensure handler stack */
- int esize;
-
- enum mrb_fiber_state status;
+ enum mrb_fiber_state status : 4;
+ mrb_bool vmexec : 1;
struct RFiber *fib;
};
-enum gc_state {
- GC_STATE_NONE = 0,
- GC_STATE_MARK,
- GC_STATE_SWEEP
+#ifdef MRB_METHOD_CACHE_SIZE
+# undef MRB_NO_METHOD_CACHE
+#else
+/* default method cache size: 256 */
+/* cache size needs to be power of 2 */
+# define MRB_METHOD_CACHE_SIZE (1<<8)
+#endif
+
+/**
+ * Function pointer type for a function callable by mruby.
+ *
+ * The arguments to the function are stored on the mrb_state. To get them see mrb_get_args
+ *
+ * @param mrb The mruby state
+ * @param self The self object
+ * @return [mrb_value] The function's return value
+ */
+typedef mrb_value (*mrb_func_t)(struct mrb_state *mrb, mrb_value self);
+
+#ifndef MRB_USE_METHOD_T_STRUCT
+typedef uintptr_t mrb_method_t;
+#else
+typedef struct {
+ uint8_t flags;
+ union {
+ struct RProc *proc;
+ mrb_func_t func;
+ };
+} mrb_method_t;
+#endif
+
+#ifndef MRB_NO_METHOD_CACHE
+struct mrb_cache_entry {
+ struct RClass *c, *c0;
+ mrb_sym mid;
+ mrb_method_t m;
};
+#endif
struct mrb_jmpbuf;
@@ -116,9 +239,9 @@ typedef struct mrb_state {
struct mrb_context *c;
struct mrb_context *root_c;
+ struct iv_tbl *globals; /* global variable table */
struct RObject *exc; /* exception */
- struct iv_tbl *globals; /* global variable table */
struct RObject *top_self;
struct RClass *object_class; /* Object class */
@@ -128,53 +251,50 @@ typedef struct mrb_state {
struct RClass *string_class;
struct RClass *array_class;
struct RClass *hash_class;
+ struct RClass *range_class;
+#ifndef MRB_NO_FLOAT
struct RClass *float_class;
- struct RClass *fixnum_class;
+#endif
+ struct RClass *integer_class;
struct RClass *true_class;
struct RClass *false_class;
struct RClass *nil_class;
struct RClass *symbol_class;
struct RClass *kernel_module;
- struct heap_page *heaps; /* heaps for GC */
- struct heap_page *sweeps;
- struct heap_page *free_heaps;
- size_t live; /* count of live objects */
-#ifdef MRB_GC_FIXED_ARENA
- struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */
-#else
- struct RBasic **arena; /* GC protection array */
- int arena_capa;
+ mrb_gc gc;
+
+#ifndef MRB_NO_METHOD_CACHE
+ struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE];
#endif
- int arena_idx;
-
- enum gc_state gc_state; /* state of gc */
- int current_white_part; /* make white object by white_part */
- struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */
- struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */
- size_t gc_live_after_mark;
- size_t gc_threshold;
- int gc_interval_ratio;
- int gc_step_ratio;
- mrb_bool gc_disabled:1;
- mrb_bool gc_full:1;
- mrb_bool is_generational_gc_mode:1;
- mrb_bool out_of_memory:1;
- size_t majorgc_old_threshold;
- struct alloca_header *mems;
mrb_sym symidx;
- struct kh_n2s *name2sym; /* symbol table */
+ const char **symtbl;
+ uint8_t *symlink;
+ uint8_t *symflags;
+ mrb_sym symhash[256];
+ size_t symcapa;
+#ifndef MRB_USE_ALL_SYMBOLS
+ char symbuf[8]; /* buffer for small symbol names */
+#endif
+
+#ifdef MRB_USE_DEBUG_HOOK
+ void (*code_fetch_hook)(struct mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
+ void (*debug_op_hook)(struct mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
+#endif
-#ifdef ENABLE_DEBUG
- void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs);
- void (*debug_op_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs);
+#ifdef MRB_BYTECODE_DECODE_OPTION
+ mrb_code (*bytecode_decoder)(struct mrb_state* mrb, mrb_code code);
#endif
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 overflow error */
+#endif
void *ud; /* auxiliary data */
@@ -183,81 +303,726 @@ typedef struct mrb_state {
#else
mrb_atexit_func *atexit_stack;
#endif
- mrb_int atexit_stack_len;
+ uint16_t atexit_stack_len;
} mrb_state;
-#if __STDC_VERSION__ >= 201112L
-# define mrb_noreturn _Noreturn
-#elif defined __GNUC__ && !defined __STRICT_ANSI__
-# define mrb_noreturn __attribute__((noreturn))
-#elif defined _MSC_VER
-# define mrb_noreturn __declspec(noreturn)
-#else
-# define mrb_noreturn
-#endif
-
-typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value);
-struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*);
-struct RClass *mrb_define_module(mrb_state *, const char*);
-mrb_value mrb_singleton_class(mrb_state*, mrb_value);
-void mrb_include_module(mrb_state*, struct RClass*, struct RClass*);
-
-void mrb_define_method(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec);
-void mrb_define_class_method(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec);
-void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec);
-void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec);
-void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value);
-void mrb_undef_method(mrb_state*, struct RClass*, const char*);
-void mrb_undef_class_method(mrb_state*, struct RClass*, const char*);
-mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv);
-#define mrb_class_new_instance(mrb,argc,argv,c) mrb_obj_new(mrb,c,argc,argv)
-mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
-struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super);
-struct RClass * mrb_module_new(mrb_state *mrb);
-mrb_bool mrb_class_defined(mrb_state *mrb, const char *name);
-struct RClass * mrb_class_get(mrb_state *mrb, const char *name);
-struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name);
-struct RClass * mrb_module_get(mrb_state *mrb, const char *name);
-struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name);
-
-mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj);
-mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method);
-mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid);
-struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super);
-struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name);
-
-/* required arguments */
+/**
+ * Defines a new class.
+ *
+ * If you're creating a gem it may look something like this:
+ *
+ * !!!c
+ * void mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_class;
+ * example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class);
+ * }
+ *
+ * void mrb_example_gem_final(mrb_state* mrb) {
+ * //free(TheAnimals);
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param name The name of the defined class.
+ * @param super The new class parent.
+ * @return [struct RClass *] Reference to the newly defined class.
+ * @see mrb_define_class_under
+ */
+MRB_API struct RClass *mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super);
+MRB_API struct RClass *mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super);
+
+/**
+ * Defines a new module.
+ *
+ * @param mrb The current mruby state.
+ * @param name The name of the module.
+ * @return [struct RClass *] Reference to the newly defined module.
+ */
+MRB_API struct RClass *mrb_define_module(mrb_state *mrb, const char *name);
+MRB_API struct RClass *mrb_define_module_id(mrb_state *mrb, mrb_sym name);
+
+MRB_API mrb_value mrb_singleton_class(mrb_state *mrb, mrb_value val);
+MRB_API struct RClass *mrb_singleton_class_ptr(mrb_state *mrb, mrb_value val);
+
+/**
+ * Include a module in another class or module.
+ * Equivalent to:
+ *
+ * module B
+ * include A
+ * end
+ * @param mrb The current mruby state.
+ * @param cla A reference to module or a class.
+ * @param included A reference to the module to be included.
+ */
+MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *cla, struct RClass *included);
+
+/**
+ * Prepends a module in another class or module.
+ *
+ * Equivalent to:
+ * module B
+ * prepend A
+ * end
+ * @param mrb The current mruby state.
+ * @param cla A reference to module or a class.
+ * @param prepended A reference to the module to be prepended.
+ */
+MRB_API void mrb_prepend_module(mrb_state *mrb, struct RClass *cla, struct RClass *prepended);
+
+/**
+ * Defines a global function in ruby.
+ *
+ * If you're creating a gem it may look something like this
+ *
+ * Example:
+ *
+ * mrb_value example_method(mrb_state* mrb, mrb_value self)
+ * {
+ * puts("Executing example command!");
+ * return self;
+ * }
+ *
+ * void mrb_example_gem_init(mrb_state* mrb)
+ * {
+ * mrb_define_method(mrb, mrb->kernel_module, "example_method", example_method, MRB_ARGS_NONE());
+ * }
+ *
+ * @param mrb The MRuby state reference.
+ * @param cla The class pointer where the method will be defined.
+ * @param name The name of the method being defined.
+ * @param func The function pointer to the method definition.
+ * @param aspec The method parameters declaration.
+ */
+MRB_API void mrb_define_method(mrb_state *mrb, struct RClass *cla, const char *name, mrb_func_t func, mrb_aspec aspec);
+MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec);
+
+/**
+ * Defines a class method.
+ *
+ * Example:
+ *
+ * # Ruby style
+ * class Foo
+ * def Foo.bar
+ * end
+ * end
+ * // C style
+ * mrb_value bar_method(mrb_state* mrb, mrb_value self){
+ * return mrb_nil_value();
+ * }
+ * void mrb_example_gem_init(mrb_state* mrb){
+ * struct RClass *foo;
+ * foo = mrb_define_class(mrb, "Foo", mrb->object_class);
+ * mrb_define_class_method(mrb, foo, "bar", bar_method, MRB_ARGS_NONE());
+ * }
+ * @param mrb The MRuby state reference.
+ * @param cla The class where the class method will be defined.
+ * @param name The name of the class method being defined.
+ * @param fun The function pointer to the class method definition.
+ * @param aspec The method parameters declaration.
+ */
+MRB_API void mrb_define_class_method(mrb_state *mrb, struct RClass *cla, const char *name, mrb_func_t fun, mrb_aspec aspec);
+MRB_API void mrb_define_class_method_id(mrb_state *mrb, struct RClass *cla, mrb_sym name, mrb_func_t fun, mrb_aspec aspec);
+
+/**
+ * Defines a singleton method
+ *
+ * @see mrb_define_class_method
+ */
+MRB_API void mrb_define_singleton_method(mrb_state *mrb, struct RObject *cla, const char *name, mrb_func_t fun, mrb_aspec aspec);
+MRB_API void mrb_define_singleton_method_id(mrb_state *mrb, struct RObject *cla, mrb_sym name, mrb_func_t fun, mrb_aspec aspec);
+
+/**
+ * Defines a module function.
+ *
+ * Example:
+ *
+ * # Ruby style
+ * module Foo
+ * def Foo.bar
+ * end
+ * end
+ * // C style
+ * mrb_value bar_method(mrb_state* mrb, mrb_value self){
+ * return mrb_nil_value();
+ * }
+ * void mrb_example_gem_init(mrb_state* mrb){
+ * struct RClass *foo;
+ * foo = mrb_define_module(mrb, "Foo");
+ * mrb_define_module_function(mrb, foo, "bar", bar_method, MRB_ARGS_NONE());
+ * }
+ * @param mrb The MRuby state reference.
+ * @param cla The module where the module function will be defined.
+ * @param name The name of the module function being defined.
+ * @param fun The function pointer to the module function definition.
+ * @param aspec The method parameters declaration.
+ */
+MRB_API void mrb_define_module_function(mrb_state *mrb, struct RClass *cla, const char *name, mrb_func_t fun, mrb_aspec aspec);
+MRB_API void mrb_define_module_function_id(mrb_state *mrb, struct RClass *cla, mrb_sym name, mrb_func_t fun, mrb_aspec aspec);
+
+/**
+ * Defines a constant.
+ *
+ * Example:
+ *
+ * # Ruby style
+ * class ExampleClass
+ * AGE = 22
+ * end
+ * // C style
+ * #include <stdio.h>
+ * #include <mruby.h>
+ *
+ * void
+ * mrb_example_gem_init(mrb_state* mrb){
+ * mrb_define_const(mrb, mrb->kernel_module, "AGE", mrb_fixnum_value(22));
+ * }
+ *
+ * mrb_value
+ * mrb_example_gem_final(mrb_state* mrb){
+ * }
+ * @param mrb The MRuby state reference.
+ * @param cla A class or module the constant is defined in.
+ * @param name The name of the constant being defined.
+ * @param val The value for the constant.
+ */
+MRB_API void mrb_define_const(mrb_state* mrb, struct RClass* cla, const char *name, mrb_value val);
+MRB_API void mrb_define_const_id(mrb_state* mrb, struct RClass* cla, mrb_sym name, mrb_value val);
+
+/**
+ * Undefines a method.
+ *
+ * Example:
+ *
+ * # Ruby style
+ *
+ * class ExampleClassA
+ * def example_method
+ * "example"
+ * end
+ * end
+ * ExampleClassA.new.example_method # => example
+ *
+ * class ExampleClassB < ExampleClassA
+ * undef_method :example_method
+ * end
+ *
+ * ExampleClassB.new.example_method # => undefined method 'example_method' for ExampleClassB (NoMethodError)
+ *
+ * // C style
+ * #include <stdio.h>
+ * #include <mruby.h>
+ *
+ * mrb_value
+ * mrb_example_method(mrb_state *mrb){
+ * return mrb_str_new_lit(mrb, "example");
+ * }
+ *
+ * void
+ * mrb_example_gem_init(mrb_state* mrb){
+ * struct RClass *example_class_a;
+ * struct RClass *example_class_b;
+ * struct RClass *example_class_c;
+ *
+ * example_class_a = mrb_define_class(mrb, "ExampleClassA", mrb->object_class);
+ * mrb_define_method(mrb, example_class_a, "example_method", mrb_example_method, MRB_ARGS_NONE());
+ * example_class_b = mrb_define_class(mrb, "ExampleClassB", example_class_a);
+ * example_class_c = mrb_define_class(mrb, "ExampleClassC", example_class_b);
+ * mrb_undef_method(mrb, example_class_c, "example_method");
+ * }
+ *
+ * mrb_example_gem_final(mrb_state* mrb){
+ * }
+ * @param mrb The mruby state reference.
+ * @param cla The class the method will be undefined from.
+ * @param name The name of the method to be undefined.
+ */
+MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *cla, const char *name);
+MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym);
+
+/**
+ * Undefine a class method.
+ * Example:
+ *
+ * # Ruby style
+ * class ExampleClass
+ * def self.example_method
+ * "example"
+ * end
+ * end
+ *
+ * ExampleClass.example_method
+ *
+ * // C style
+ * #include <stdio.h>
+ * #include <mruby.h>
+ *
+ * mrb_value
+ * mrb_example_method(mrb_state *mrb){
+ * return mrb_str_new_lit(mrb, "example");
+ * }
+ *
+ * void
+ * mrb_example_gem_init(mrb_state* mrb){
+ * struct RClass *example_class;
+ * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class);
+ * mrb_define_class_method(mrb, example_class, "example_method", mrb_example_method, MRB_ARGS_NONE());
+ * mrb_undef_class_method(mrb, example_class, "example_method");
+ * }
+ *
+ * void
+ * mrb_example_gem_final(mrb_state* mrb){
+ * }
+ * @param mrb The mruby state reference.
+ * @param cls A class the class method will be undefined from.
+ * @param name The name of the class method to be undefined.
+ */
+MRB_API void mrb_undef_class_method(mrb_state *mrb, struct RClass *cls, const char *name);
+MRB_API void mrb_undef_class_method_id(mrb_state *mrb, struct RClass *cls, mrb_sym name);
+
+/**
+ * Initialize a new object instance of c class.
+ *
+ * Example:
+ *
+ * # Ruby style
+ * class ExampleClass
+ * end
+ *
+ * p ExampleClass # => #<ExampleClass:0x9958588>
+ * // C style
+ * #include <stdio.h>
+ * #include <mruby.h>
+ *
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_class;
+ * mrb_value obj;
+ * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class); # => class ExampleClass; end
+ * obj = mrb_obj_new(mrb, example_class, 0, NULL); # => ExampleClass.new
+ * mrb_p(mrb, obj); // => Kernel#p
+ * }
+ * @param mrb The current mruby state.
+ * @param c Reference to the class of the new object.
+ * @param argc Number of arguments in argv
+ * @param argv Array of mrb_value to initialize the object
+ * @return [mrb_value] The newly initialized object
+ */
+MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv);
+
+/** @see mrb_obj_new */
+MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const mrb_value *argv, struct RClass *c)
+{
+ return mrb_obj_new(mrb,c,argc,argv);
+}
+
+/**
+ * Creates a new instance of Class, Class.
+ *
+ * Example:
+ *
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_class;
+ *
+ * mrb_value obj;
+ * example_class = mrb_class_new(mrb, mrb->object_class);
+ * obj = mrb_obj_new(mrb, example_class, 0, NULL); // => #<#<Class:0x9a945b8>:0x9a94588>
+ * mrb_p(mrb, obj); // => Kernel#p
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param super The super class or parent.
+ * @return [struct RClass *] Reference to the new class.
+ */
+MRB_API struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super);
+
+/**
+ * Creates a new module, Module.
+ *
+ * Example:
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_module;
+ *
+ * example_module = mrb_module_new(mrb);
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @return [struct RClass *] Reference to the new module.
+ */
+MRB_API struct RClass * mrb_module_new(mrb_state *mrb);
+
+/**
+ * Returns an mrb_bool. True if class was defined, and false if the class was not defined.
+ *
+ * Example:
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_class;
+ * mrb_bool cd;
+ *
+ * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class);
+ * cd = mrb_class_defined(mrb, "ExampleClass");
+ *
+ * // If mrb_class_defined returns 1 then puts "True"
+ * // If mrb_class_defined returns 0 then puts "False"
+ * if (cd == 1){
+ * puts("True");
+ * }
+ * else {
+ * puts("False");
+ * }
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param name A string representing the name of the class.
+ * @return [mrb_bool] A boolean value.
+ */
+MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name);
+MRB_API mrb_bool mrb_class_defined_id(mrb_state *mrb, mrb_sym name);
+
+/**
+ * Gets a class.
+ * @param mrb The current mruby state.
+ * @param name The name of the class.
+ * @return [struct RClass *] A reference to the class.
+*/
+MRB_API struct RClass* mrb_class_get(mrb_state *mrb, const char *name);
+MRB_API struct RClass* mrb_class_get_id(mrb_state *mrb, mrb_sym name);
+
+/**
+ * Gets a exception class.
+ * @param mrb The current mruby state.
+ * @param name The name of the class.
+ * @return [struct RClass *] A reference to the class.
+*/
+MRB_API struct RClass* mrb_exc_get_id(mrb_state *mrb, mrb_sym name);
+#define mrb_exc_get(mrb, name) mrb_exc_get_id(mrb, mrb_intern_cstr(mrb, name))
+
+/**
+ * Returns an mrb_bool. True if inner class was defined, and false if the inner class was not defined.
+ *
+ * Example:
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_outer, *example_inner;
+ * mrb_bool cd;
+ *
+ * example_outer = mrb_define_module(mrb, "ExampleOuter");
+ *
+ * example_inner = mrb_define_class_under(mrb, example_outer, "ExampleInner", mrb->object_class);
+ * cd = mrb_class_defined_under(mrb, example_outer, "ExampleInner");
+ *
+ * // 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");
+ * }
+ * else {
+ * puts("False");
+ * }
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param outer The name of the outer class.
+ * @param name A string representing the name of the inner class.
+ * @return [mrb_bool] A boolean value.
+ */
+MRB_API mrb_bool mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name);
+MRB_API mrb_bool mrb_class_defined_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name);
+
+/**
+ * Gets a child class.
+ * @param mrb The current mruby state.
+ * @param outer The name of the parent class.
+ * @param name The name of the class.
+ * @return [struct RClass *] A reference to the class.
+*/
+MRB_API struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name);
+MRB_API struct RClass * mrb_class_get_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name);
+
+/**
+ * Gets a module.
+ * @param mrb The current mruby state.
+ * @param name The name of the module.
+ * @return [struct RClass *] A reference to the module.
+*/
+MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name);
+MRB_API struct RClass * mrb_module_get_id(mrb_state *mrb, mrb_sym name);
+
+/**
+ * Gets a module defined under another module.
+ * @param mrb The current mruby state.
+ * @param outer The name of the outer module.
+ * @param name The name of the module.
+ * @return [struct RClass *] A reference to the module.
+*/
+MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name);
+MRB_API struct RClass * mrb_module_get_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name);
+
+/* a function to raise NotImplementedError with current method name */
+MRB_API void mrb_notimplement(mrb_state*);
+/* a function to be replacement of unimplemented method */
+MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value);
+
+/**
+ * Duplicate an object.
+ *
+ * Equivalent to:
+ * Object#dup
+ * @param mrb The current mruby state.
+ * @param obj Object to be duplicate.
+ * @return [mrb_value] The newly duplicated object.
+ */
+MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj);
+
+/**
+ * Returns true if obj responds to the given method. If the method was defined for that
+ * class it returns true, it returns false otherwise.
+ *
+ * Example:
+ * # Ruby style
+ * class ExampleClass
+ * def example_method
+ * end
+ * end
+ *
+ * ExampleClass.new.respond_to?(:example_method) # => true
+ *
+ * // C style
+ * void
+ * mrb_example_gem_init(mrb_state* mrb) {
+ * struct RClass *example_class;
+ * mrb_sym mid;
+ * mrb_bool obj_resp;
+ *
+ * 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_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"
+ * // If mrb_obj_respond_to returns 0 then puts "False"
+ * if (obj_resp == 1) {
+ * puts("True");
+ * }
+ * else if (obj_resp == 0) {
+ * puts("False");
+ * }
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param c A reference to a class.
+ * @param mid A symbol referencing a method id.
+ * @return [mrb_bool] A boolean value.
+ */
+MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid);
+
+/**
+ * Defines a new class under a given module
+ *
+ * @param mrb The current mruby state.
+ * @param outer Reference to the module under which the new class will be defined
+ * @param name The name of the defined class
+ * @param super The new class parent
+ * @return [struct RClass *] Reference to the newly defined class
+ * @see mrb_define_class
+ */
+MRB_API struct RClass* mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super);
+MRB_API struct RClass* mrb_define_class_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name, struct RClass *super);
+
+MRB_API struct RClass* mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name);
+MRB_API struct RClass* mrb_define_module_under_id(mrb_state *mrb, struct RClass *outer, mrb_sym name);
+
+/**
+ * Function requires n arguments.
+ *
+ * @param n
+ * The number of required arguments.
+ */
#define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18)
-/* optional arguments */
+
+/**
+ * Function takes n optional arguments
+ *
+ * @param n
+ * The number of optional arguments.
+ */
#define MRB_ARGS_OPT(n) ((mrb_aspec)((n)&0x1f) << 13)
-/* mandatory and optinal arguments */
+
+/**
+ * Function takes n1 mandatory arguments and n2 optional arguments
+ *
+ * @param n1
+ * The number of required arguments.
+ * @param n2
+ * The number of optional arguments.
+ */
#define MRB_ARGS_ARG(n1,n2) (MRB_ARGS_REQ(n1)|MRB_ARGS_OPT(n2))
-/* rest argument */
+/** rest argument */
#define MRB_ARGS_REST() ((mrb_aspec)(1 << 12))
-/* required arguments after rest */
+
+/** required arguments after rest */
#define MRB_ARGS_POST(n) ((mrb_aspec)((n)&0x1f) << 7)
-/* keyword arguments (n of keys, kdict) */
+
+/** keyword arguments (n of keys, kdict) */
#define MRB_ARGS_KEY(n1,n2) ((mrb_aspec)((((n1)&0x1f) << 2) | ((n2)?(1<<1):0)))
-/* block argument */
+
+/**
+ * Function takes a block argument
+ */
#define MRB_ARGS_BLOCK() ((mrb_aspec)1)
-/* accept any number of arguments */
+/**
+ * Function accepts any number of arguments
+ */
#define MRB_ARGS_ANY() MRB_ARGS_REST()
-/* accept no arguments */
+
+/**
+ * Function accepts no arguments
+ */
#define MRB_ARGS_NONE() ((mrb_aspec)0)
-/* compatibility macros; will be removed */
-#define ARGS_REQ(n) MRB_ARGS_REQ(n)
-#define ARGS_OPT(n) MRB_ARGS_OPT(n)
-#define ARGS_REST() MRB_ARGS_REST()
-#define ARGS_POST(n) MRB_ARGS_POST()
-#define ARGS_KEY(n1,n2) MRB_ARGS_KEY(n1,n2)
-#define ARGS_BLOCK() MRB_ARGS_BLOCK()
-#define ARGS_ANY() MRB_ARGS_ANY()
-#define ARGS_NONE() MRB_ARGS_NONE()
+/**
+ * Format specifiers for {mrb_get_args} function
+ *
+ * Must be a C string composed of the following format specifiers:
+ *
+ * | char | Ruby type | C types | Notes |
+ * |:----:|----------------|-------------------|----------------------------------------------------|
+ * | `o` | {Object} | {mrb_value} | Could be used to retrieve any type of argument |
+ * | `C` | {Class}/{Module} | {mrb_value} | when `!` follows, the value may be `nil` |
+ * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` |
+ * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` |
+ * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` |
+ * | `s` | {String} | const char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` |
+ * | `z` | {String} | const char * | `NULL` terminated string; `z!` gives `NULL` for `nil` |
+ * | `a` | {Array} | const {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` |
+ * | `c` | {Class}/{Module} | strcut RClass * | `c!` gives `NULL` for `nil` |
+ * | `f` | {Integer}/{Float} | {mrb_float} | |
+ * | `i` | {Integer}/{Float} | {mrb_int} | |
+ * | `b` | boolean | {mrb_bool} | |
+ * | `n` | {String}/{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; when `!` follows, the value may be `nil` |
+ * | `I` | inline struct | void *, struct RClass | `I!` gives `NULL` for `nil` |
+ * | `&` | block | {mrb_value} | &! raises exception if no block given. |
+ * | `*` | rest arguments | const {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; `*!` avoid copy of the stack. |
+ * | <code>\|</code> | optional | | After this spec following specs would be optional. |
+ * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. |
+ * | `:` | keyword args | {mrb_kwargs} const | Get keyword arguments. @see mrb_kwargs |
+ *
+ * @see mrb_get_args
+ *
+ * Immediately after format specifiers it can add format modifiers:
+ *
+ * | char | Notes |
+ * |:----:|-----------------------------------------------------------------------------------------|
+ * | `!` | Switch to the alternate mode; The behaviour changes depending on the format specifier |
+ * | `+` | Request a not frozen object; However, except nil value |
+ */
+typedef const char *mrb_args_format;
+
+/**
+ * Get keyword arguments by `mrb_get_args()` with `:` specifier.
+ *
+ * `mrb_kwargs::num` indicates that the number of keyword values.
+ *
+ * `mrb_kwargs::values` is an object array, and the keyword argument corresponding to the string array is assigned.
+ * Note that `undef` is assigned if there is no keyword argument corresponding to `mrb_kwargs::optional`.
+ *
+ * `mrb_kwargs::table` accepts a string array.
+ *
+ * `mrb_kwargs::required` indicates that the specified number of keywords starting from the beginning of the string array are required.
+ *
+ * `mrb_kwargs::rest` is the remaining keyword argument that can be accepted as `**rest` in Ruby.
+ * If `NULL` is specified, `ArgumentError` is raised when there is an undefined keyword.
+ *
+ * Examples:
+ *
+ * // def method(a: 1, b: 2)
+ *
+ * uint32_t kw_num = 2;
+ * const char *kw_names[kw_num] = { "a", "b" };
+ * uint32_t kw_required = 0;
+ * mrb_value kw_values[kw_num];
+ * const mrb_kwargs kwargs = { kw_num, kw_required, kw_names, kw_values, NULL };
+ *
+ * mrb_get_args(mrb, ":", &kwargs);
+ * if (mrb_undef_p(kw_values[0])) { kw_values[0] = mrb_fixnum_value(1); }
+ * if (mrb_undef_p(kw_values[1])) { kw_values[1] = mrb_fixnum_value(2); }
+ *
+ *
+ * // def method(str, x:, y: 2, z: "default string", **opts)
+ *
+ * mrb_value str, kw_rest;
+ * uint32_t kw_num = 3;
+ * const mrb_sym kw_names[kw_num] = { MRB_SYM(x), MRB_SYM(y), MRB_SYM(z) };
+ * uint32_t kw_required = 1;
+ * mrb_value kw_values[kw_num];
+ * const mrb_kwargs kwargs = { kw_num, kw_required, kw_names, kw_values, &kw_rest };
+ *
+ * mrb_get_args(mrb, "S:", &str, &kwargs);
+ * // or: mrb_get_args(mrb, ":S", &kwargs, &str);
+ * if (mrb_undef_p(kw_values[1])) { kw_values[1] = mrb_fixnum_value(2); }
+ * if (mrb_undef_p(kw_values[2])) { kw_values[2] = mrb_str_new_cstr(mrb, "default string"); }
+ */
+typedef struct mrb_kwargs mrb_kwargs;
+
+struct mrb_kwargs
+{
+ uint32_t num; /* number of keyword arguments */
+ uint32_t required; /* number of required keyword arguments */
+ const mrb_sym *table; /* C array of symbols for keyword names */
+ mrb_value *values; /* keyword argument values */
+ mrb_value *rest; /* keyword rest (dict) */
+};
-mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...);
+/**
+ * Retrieve arguments from mrb_state.
+ *
+ * @param mrb The current MRuby state.
+ * @param format is a list of format specifiers
+ * @param ... The passing variadic arguments must be a pointer of retrieving type.
+ * @return the number of arguments retrieved.
+ * @see mrb_args_format
+ * @see mrb_kwargs
+ */
+MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...);
+
+MRB_INLINE mrb_sym
+mrb_get_mid(mrb_state *mrb) /* get method symbol */
+{
+ return mrb->c->ci->mid;
+}
+
+/**
+ * Retrieve number of arguments from mrb_state.
+ *
+ * Correctly handles *splat arguments.
+ */
+MRB_API mrb_int mrb_get_argc(mrb_state *mrb);
+
+/**
+ * Retrieve an array of arguments from mrb_state.
+ *
+ * Correctly handles *splat arguments.
+ */
+MRB_API const mrb_value *mrb_get_argv(mrb_state *mrb);
+
+/**
+ * Retrieve the first and only argument from mrb_state.
+ * Raises ArgumentError unless the number of arguments is exactly one.
+ *
+ * Correctly handles *splat arguments.
+ */
+MRB_API mrb_value mrb_get_arg1(mrb_state *mrb);
+
+/**
+ * Check if a block argument is given from mrb_state.
+ */
+MRB_API mrb_bool mrb_block_given_p(mrb_state *mrb);
/* `strlen` for character string literals (use with caution or `strlen` instead)
Adjacent string literals are concatenated in C/C++ in translation phase 6.
@@ -267,191 +1032,457 @@ mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...);
*/
#define mrb_strlen_lit(lit) (sizeof(lit "") - 1)
-mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...);
-mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*);
-mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*, mrb_value);
-mrb_sym mrb_intern_cstr(mrb_state*,const char*);
-mrb_sym mrb_intern(mrb_state*,const char*,size_t);
-mrb_sym mrb_intern_static(mrb_state*,const char*,size_t);
-#define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, lit, mrb_strlen_lit(lit))
-mrb_sym mrb_intern_str(mrb_state*,mrb_value);
-mrb_value mrb_check_intern_cstr(mrb_state*,const char*);
-mrb_value mrb_check_intern(mrb_state*,const char*,size_t);
-mrb_value mrb_check_intern_str(mrb_state*,mrb_value);
-const char *mrb_sym2name(mrb_state*,mrb_sym);
-const char *mrb_sym2name_len(mrb_state*,mrb_sym,mrb_int*);
-mrb_value mrb_sym2str(mrb_state*,mrb_sym);
-
-void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */
-void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */
-void *mrb_realloc(mrb_state*, void*, size_t); /* ditto */
-void *mrb_realloc_simple(mrb_state*, void*, size_t); /* return NULL if no memory available */
-void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory available */
-struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*);
-void mrb_free(mrb_state*, void*);
-
-mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len);
-mrb_value mrb_str_new_cstr(mrb_state*, const char*);
-mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len);
+/**
+ * Call existing ruby functions.
+ *
+ * Example:
+ *
+ * #include <stdio.h>
+ * #include <mruby.h>
+ * #include "mruby/compile.h"
+ *
+ * int
+ * main()
+ * {
+ * mrb_int i = 99;
+ * mrb_state *mrb = mrb_open();
+ *
+ * if (!mrb) { }
+ * FILE *fp = fopen("test.rb","r");
+ * mrb_value obj = mrb_load_file(mrb,fp);
+ * mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i));
+ * mrb_funcall_id(mrb, obj, MRB_SYM(method_name), 1, mrb_fixnum_value(i));
+ * fclose(fp);
+ * mrb_close(mrb);
+ * }
+ *
+ * @param mrb The current mruby state.
+ * @param val A reference to an mruby value.
+ * @param name The name of the method.
+ * @param argc The number of arguments the method has.
+ * @param ... Variadic values(not type safe!).
+ * @return [mrb_value] mruby function value.
+ */
+MRB_API mrb_value mrb_funcall(mrb_state *mrb, mrb_value val, const char *name, mrb_int argc, ...);
+MRB_API mrb_value mrb_funcall_id(mrb_state *mrb, mrb_value val, mrb_sym mid, mrb_int argc, ...);
+/**
+ * Call existing ruby functions. This is basically the type safe version of mrb_funcall.
+ *
+ * #include <stdio.h>
+ * #include <mruby.h>
+ * #include "mruby/compile.h"
+ * int
+ * main()
+ * {
+ * mrb_state *mrb = mrb_open();
+ * mrb_value obj = mrb_fixnum_value(1);
+ *
+ * if (!mrb) { }
+ *
+ * FILE *fp = fopen("test.rb","r");
+ * mrb_value obj = mrb_load_file(mrb,fp);
+ * mrb_funcall_argv(mrb, obj, MRB_SYM(method_name), 1, &obj); // Calling ruby function from test.rb.
+ * fclose(fp);
+ * mrb_close(mrb);
+ * }
+ * @param mrb The current mruby state.
+ * @param val A reference to an mruby value.
+ * @param name_sym The symbol representing the method.
+ * @param argc The number of arguments the method has.
+ * @param obj Pointer to the object.
+ * @return [mrb_value] mrb_value mruby function value.
+ * @see mrb_funcall
+ */
+MRB_API mrb_value mrb_funcall_argv(mrb_state *mrb, mrb_value val, mrb_sym name, mrb_int argc, const mrb_value *argv);
+/**
+ * Call existing ruby functions with a block.
+ */
+MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value val, mrb_sym name, mrb_int argc, const mrb_value *argv, mrb_value block);
+/**
+ * Create a symbol from C string. But usually it's better to use MRB_SYM,
+ * MRB_OPSYM, MRB_CVSYM, MRB_IVSYM, MRB_SYM_B, MRB_SYM_Q, MRB_SYM_E macros.
+ *
+ * Example:
+ *
+ * # Ruby style:
+ * :pizza # => :pizza
+ *
+ * // C style:
+ * mrb_sym sym1 = mrb_intern_lit(mrb, "pizza"); // => :pizza
+ * mrb_sym sym2 = MRB_SYM(pizza); // => :pizza
+ * mrb_sym sym3 = MRB_SYM_Q(pizza); // => :pizza?
+ *
+ * @param mrb The current mruby state.
+ * @param str The string to be symbolized
+ * @return [mrb_sym] mrb_sym A symbol.
+ */
+MRB_API mrb_sym mrb_intern_cstr(mrb_state *mrb, const char* str);
+MRB_API mrb_sym mrb_intern(mrb_state*,const char*,size_t);
+MRB_API mrb_sym mrb_intern_static(mrb_state*,const char*,size_t);
+#define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, (lit ""), mrb_strlen_lit(lit))
+MRB_API mrb_sym mrb_intern_str(mrb_state*,mrb_value);
+/* mrb_intern_check series functions returns 0 if the symbol is not defined */
+MRB_API mrb_sym mrb_intern_check_cstr(mrb_state*,const char*);
+MRB_API mrb_sym mrb_intern_check(mrb_state*,const char*,size_t);
+MRB_API mrb_sym mrb_intern_check_str(mrb_state*,mrb_value);
+/* mrb_check_intern series functions returns nil if the symbol is not defined */
+/* otherwise returns mrb_value */
+MRB_API mrb_value mrb_check_intern_cstr(mrb_state*,const char*);
+MRB_API mrb_value mrb_check_intern(mrb_state*,const char*,size_t);
+MRB_API mrb_value mrb_check_intern_str(mrb_state*,mrb_value);
+MRB_API const char *mrb_sym_name(mrb_state*,mrb_sym);
+MRB_API const char *mrb_sym_name_len(mrb_state*,mrb_sym,mrb_int*);
+MRB_API const char *mrb_sym_dump(mrb_state*,mrb_sym);
+MRB_API mrb_value mrb_sym_str(mrb_state*,mrb_sym);
+#define mrb_sym2name(mrb,sym) mrb_sym_name(mrb,sym)
+#define mrb_sym2name_len(mrb,sym,len) mrb_sym_name_len(mrb,sym,len)
+#define mrb_sym2str(mrb,sym) mrb_sym_str(mrb,sym)
+
+MRB_API void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */
+MRB_API void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */
+MRB_API void *mrb_realloc(mrb_state*, void*, size_t); /* ditto */
+MRB_API void *mrb_realloc_simple(mrb_state*, void*, size_t); /* return NULL if no memory available */
+MRB_API void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory available */
+MRB_API struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*);
+MRB_API void mrb_free(mrb_state*, void*);
+
+/**
+ * Allocates a Ruby object that matches the constant literal defined in
+ * `enum mrb_vtype` and returns a pointer to the corresponding C type.
+ *
+ * @param mrb The current mruby state
+ * @param tt The constant literal of `enum mrb_vtype`
+ * @param klass A Class object
+ * @return Reference to the newly created object
+ */
+#define MRB_OBJ_ALLOC(mrb, tt, klass) ((MRB_VTYPE_TYPEOF(tt)*)mrb_obj_alloc(mrb, tt, klass))
+
+MRB_API mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len);
+
+/**
+ * Turns a C string into a Ruby string value.
+ */
+MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*);
+MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len);
#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit))
-mrb_state* mrb_open(void);
-mrb_state* mrb_open_allocf(mrb_allocf, void *ud);
-mrb_state* mrb_open_core(mrb_allocf, void *ud);
-void mrb_close(mrb_state*);
-
-void* mrb_default_allocf(mrb_state*, void*, size_t, void*);
-
-mrb_value mrb_top_self(mrb_state *);
-mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value);
-mrb_value mrb_toplevel_run(mrb_state*, struct RProc*);
-mrb_value mrb_context_run(mrb_state*, struct RProc*, mrb_value, unsigned int);
-
-void mrb_p(mrb_state*, mrb_value);
-mrb_int mrb_obj_id(mrb_value obj);
-mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name);
-
-mrb_bool mrb_obj_eq(mrb_state*, mrb_value, mrb_value);
-mrb_bool mrb_obj_equal(mrb_state*, mrb_value, mrb_value);
-mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
-mrb_value mrb_Integer(mrb_state *mrb, mrb_value val);
-mrb_value mrb_Float(mrb_state *mrb, mrb_value val);
-mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
-mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
-
-void mrb_garbage_collect(mrb_state*);
-void mrb_full_gc(mrb_state*);
-void mrb_incremental_gc(mrb_state *);
-int mrb_gc_arena_save(mrb_state*);
-void mrb_gc_arena_restore(mrb_state*,int);
-void mrb_gc_mark(mrb_state*,struct RBasic*);
+MRB_API mrb_value mrb_obj_freeze(mrb_state*, mrb_value);
+#define mrb_str_new_frozen(mrb,p,len) mrb_obj_freeze(mrb,mrb_str_new(mrb,p,len))
+#define mrb_str_new_cstr_frozen(mrb,p) mrb_obj_freeze(mrb,mrb_str_new_cstr(mrb,p))
+#define mrb_str_new_static_frozen(mrb,p,len) mrb_obj_freeze(mrb,mrb_str_new_static(mrb,p,len))
+#define mrb_str_new_lit_frozen(mrb,lit) mrb_obj_freeze(mrb,mrb_str_new_lit(mrb,lit))
+
+#ifdef _WIN32
+MRB_API char* mrb_utf8_from_locale(const char *p, int len);
+MRB_API char* mrb_locale_from_utf8(const char *p, int len);
+#define mrb_locale_free(p) free(p)
+#define mrb_utf8_free(p) free(p)
+#else
+#define mrb_utf8_from_locale(p, l) ((char*)(p))
+#define mrb_locale_from_utf8(p, l) ((char*)(p))
+#define mrb_locale_free(p)
+#define mrb_utf8_free(p)
+#endif
+
+/**
+ * Creates new mrb_state.
+ *
+ * @return
+ * Pointer to the newly created mrb_state.
+ */
+MRB_API mrb_state* mrb_open(void);
+
+/**
+ * Create new mrb_state with custom allocators.
+ *
+ * @param f
+ * Reference to the allocation function.
+ * @param ud
+ * User data will be passed to custom allocator f.
+ * If user data isn't required just pass NULL.
+ * @return
+ * Pointer to the newly created mrb_state.
+ */
+MRB_API mrb_state* mrb_open_allocf(mrb_allocf f, void *ud);
+
+/**
+ * Create new mrb_state with just the MRuby core
+ *
+ * @param f
+ * Reference to the allocation function.
+ * Use mrb_default_allocf for the default
+ * @param ud
+ * User data will be passed to custom allocator f.
+ * If user data isn't required just pass NULL.
+ * @return
+ * Pointer to the newly created mrb_state.
+ */
+MRB_API mrb_state* mrb_open_core(mrb_allocf f, void *ud);
+
+/**
+ * Closes and frees a mrb_state.
+ *
+ * @param mrb
+ * Pointer to the mrb_state to be closed.
+ */
+MRB_API void mrb_close(mrb_state *mrb);
+
+/**
+ * The default allocation function.
+ *
+ * @see mrb_allocf
+ */
+MRB_API void* mrb_default_allocf(mrb_state*, void*, size_t, void*);
+
+MRB_API mrb_value mrb_top_self(mrb_state *mrb);
+MRB_API mrb_value mrb_top_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int stack_keep);
+MRB_API mrb_value mrb_vm_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int stack_keep);
+MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *iseq);
+/* compatibility macros */
+#define mrb_toplevel_run_keep(m,p,k) mrb_top_run((m),(p),mrb_top_self(m),(k))
+#define mrb_toplevel_run(m,p) mrb_toplevel_run_keep((m),(p),0)
+#define mrb_context_run(m,p,s,k) mrb_vm_run((m),(p),(s),(k))
+
+MRB_API void mrb_p(mrb_state*, mrb_value);
+MRB_API mrb_int mrb_obj_id(mrb_value obj);
+MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name);
+
+MRB_API mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value a, mrb_value b);
+MRB_API mrb_bool mrb_obj_equal(mrb_state *mrb, mrb_value a, mrb_value b);
+MRB_API mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
+#ifndef MRB_NO_FLOAT
+MRB_API mrb_value mrb_to_float(mrb_state *mrb, mrb_value val);
+#endif
+MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
+MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
+/* mrb_cmp(mrb, obj1, obj2): 1:0:-1; -2 for error */
+MRB_API mrb_int mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
+
+MRB_INLINE int
+mrb_gc_arena_save(mrb_state *mrb)
+{
+ return mrb->gc.arena_idx;
+}
+
+MRB_INLINE void
+mrb_gc_arena_restore(mrb_state *mrb, int idx)
+{
+ mrb->gc.arena_idx = idx;
+}
+
+MRB_API void mrb_garbage_collect(mrb_state*);
+MRB_API void mrb_full_gc(mrb_state*);
+MRB_API void mrb_incremental_gc(mrb_state *);
+MRB_API void mrb_gc_mark(mrb_state*,struct RBasic*);
#define mrb_gc_mark_value(mrb,val) do {\
if (!mrb_immediate_p(val)) mrb_gc_mark((mrb), mrb_basic_ptr(val)); \
} while (0)
-void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*);
+MRB_API void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*);
#define mrb_field_write_barrier_value(mrb, obj, val) do{\
if (!mrb_immediate_p(val)) mrb_field_write_barrier((mrb), (obj), mrb_basic_ptr(val)); \
} while (0)
-void mrb_write_barrier(mrb_state *, struct RBasic*);
-
-mrb_value mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method);
-mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj);
-const char * mrb_obj_classname(mrb_state *mrb, mrb_value obj);
-struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj);
-mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c);
-mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method);
-mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c);
-mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value self);
-mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self);
-
-/* need to include <ctype.h> to use these macros */
+MRB_API void mrb_write_barrier(mrb_state *, struct RBasic*);
+
+MRB_API mrb_value mrb_type_convert(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method);
+#define mrb_convert_type(mrb, val, type, tname, method) mrb_type_convert(mrb, val, type, mrb_intern_lit(mrb, method))
+MRB_API mrb_value mrb_type_convert_check(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method);
+#define mrb_check_convert_type(mrb, val, type, tname, method) mrb_type_convert_check(mrb, val, type, mrb_intern_lit(mrb, method))
+
+MRB_API mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj);
+MRB_API const char * mrb_obj_classname(mrb_state *mrb, mrb_value obj);
+MRB_API struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj);
+MRB_API mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c);
+MRB_API mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c);
+MRB_API mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value self);
+MRB_API mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self);
+
#ifndef ISPRINT
-#define ISASCII(c) (!(((int)(unsigned char)(c)) & ~0x7f))
-#define ISPRINT(c) (ISASCII(c) && isprint((int)(unsigned char)(c)))
-#define ISSPACE(c) (ISASCII(c) && isspace((int)(unsigned char)(c)))
-#define ISUPPER(c) (ISASCII(c) && isupper((int)(unsigned char)(c)))
-#define ISLOWER(c) (ISASCII(c) && islower((int)(unsigned char)(c)))
-#define ISALNUM(c) (ISASCII(c) && isalnum((int)(unsigned char)(c)))
-#define ISALPHA(c) (ISASCII(c) && isalpha((int)(unsigned char)(c)))
-#define ISDIGIT(c) (ISASCII(c) && isdigit((int)(unsigned char)(c)))
-#define ISXDIGIT(c) (ISASCII(c) && isxdigit((int)(unsigned char)(c)))
-#define TOUPPER(c) (ISASCII(c) ? toupper((int)(unsigned char)(c)) : (c))
-#define TOLOWER(c) (ISASCII(c) ? tolower((int)(unsigned char)(c)) : (c))
+#define ISASCII(c) ((unsigned)(c) <= 0x7f)
+#define ISPRINT(c) (((unsigned)(c) - 0x20) < 0x5f)
+#define ISSPACE(c) ((c) == ' ' || (unsigned)(c) - '\t' < 5)
+#define ISUPPER(c) (((unsigned)(c) - 'A') < 26)
+#define ISLOWER(c) (((unsigned)(c) - 'a') < 26)
+#define ISALPHA(c) ((((unsigned)(c) | 0x20) - 'a') < 26)
+#define ISDIGIT(c) (((unsigned)(c) - '0') < 10)
+#define ISXDIGIT(c) (ISDIGIT(c) || ((unsigned)(c) | 0x20) - 'a' < 6)
+#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#define ISCNTRL(c) ((unsigned)(c) < 0x20 || (c) == 0x7f)
+#define TOUPPER(c) (ISLOWER(c) ? ((c) & 0x5f) : (c))
+#define TOLOWER(c) (ISUPPER(c) ? ((c) | 0x20) : (c))
#endif
-mrb_value mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len);
-mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc);
-
-mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg);
-mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...);
-mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...);
-void mrb_warn(mrb_state *mrb, const char *fmt, ...);
-mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...);
-void mrb_print_backtrace(mrb_state *mrb);
-void mrb_print_error(mrb_state *mrb);
+MRB_API mrb_value mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len);
+MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc);
+
+MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg);
+MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...);
+MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...);
+MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj);
+MRB_API mrb_noreturn void mrb_argnum_error(mrb_state *mrb, mrb_int argc, int min, int max);
+MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...);
+MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...);
+MRB_API void mrb_print_backtrace(mrb_state *mrb);
+MRB_API void mrb_print_error(mrb_state *mrb);
+/* function for `raisef` formatting */
+MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap);
/* macros to get typical exception objects
note:
+ 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_NOTIMP_ERROR (mrb_class_get(mrb, "NotImplementedError"))
-#define E_FLOATDOMAIN_ERROR (mrb_class_get(mrb, "FloatDomainError"))
-
-#define E_KEY_ERROR (mrb_class_get(mrb, "KeyError"))
-
-mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
-mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
-mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c);
-
-void mrb_gc_protect(mrb_state *mrb, mrb_value obj);
-mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
-#define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val))
-void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
-
-typedef enum call_type {
- CALL_PUBLIC,
- CALL_FCALL,
- CALL_VCALL,
- CALL_TYPE_MAX
-} call_type;
-
-void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2);
-const char *mrb_class_name(mrb_state *mrb, struct RClass* klass);
-void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val);
-
-mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id);
-
-mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid);
-mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c);
-
-/* fiber functions (you need to link mruby-fiber mrbgem to use) */
-mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
-#define E_FIBER_ERROR (mrb_class_get(mrb, "FiberError"))
+#define MRB_ERROR_SYM(sym) mrb_intern_lit(mrb, #sym)
+#define E_RUNTIME_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(RuntimeError))
+#define E_TYPE_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(TypeError))
+#define E_ZERODIV_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(ZeroDivisionError))
+#define E_ARGUMENT_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(ArgumentError))
+#define E_INDEX_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(IndexError))
+#define E_RANGE_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(RangeError))
+#define E_NAME_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(NameError))
+#define E_NOMETHOD_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(NoMethodError))
+#define E_SCRIPT_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(ScriptError))
+#define E_SYNTAX_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(SyntaxError))
+#define E_LOCALJUMP_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(LocalJumpError))
+#define E_REGEXP_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(RegexpError))
+#define E_FROZEN_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(FrozenError))
+#define E_NOTIMP_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(NotImplementedError))
+#define E_KEY_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(KeyError))
+#ifndef MRB_NO_FLOAT
+# define E_FLOATDOMAIN_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(FloatDomainError))
+#endif
+
+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);
+MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c);
+
+/* continue execution to the proc */
+/* this function should always be called as the last function of a method */
+/* e.g. return mrb_yield_cont(mrb, proc, self, argc, argv); */
+mrb_value mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv);
+
+/* mrb_gc_protect() leaves the object in the arena */
+MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj);
+/* mrb_gc_register() keeps the object from GC. */
+MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj);
+/* mrb_gc_unregister() removes the object from GC root. */
+MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj);
+
+/* type conversion/check functions */
+MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value self);
+MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
+MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash);
+MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
+MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str);
+MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
+/* obsolete: use mrb_ensure_string_type() instead */
+#define mrb_string_type(mrb, str) mrb_ensure_string_type(mrb,str)
+#define mrb_to_str(mrb, str) mrb_ensure_string_type(mrb,str)
+/* obsolete: use mrb_obj_as_string() instead */
+#define mrb_str_to_str(mrb, str) mrb_obj_as_string(mrb, str)
+MRB_API mrb_value mrb_to_integer(mrb_state *mrb, mrb_value val);
+#define mrb_to_int(mrb, val) mrb_to_integer(mrb, val)
+#define mrb_as_int(mrb, val) mrb_integer(mrb_to_integer(mrb, val))
+
+/* string type checking (contrary to the name, it doesn't convert) */
+MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
+
+MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o)
+{
+ if (mrb_frozen_p((struct RBasic*)o)) mrb_frozen_error(mrb, o);
+}
+
+MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *c, const char *a, const char *b);
+MRB_API void mrb_define_alias_id(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b);
+MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass);
+MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val);
+
+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);
+
+/* obsolete function(s); will be removed */
+#define mrb_int(mrb, val) mrb_as_int(mrb, val)
+
+/**
+ * Resume a Fiber
+ *
+ * Implemented in mruby-fiber
+ */
+MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int argc, const mrb_value *argv);
+
+/**
+ * Yield a Fiber
+ *
+ * Implemented in mruby-fiber
+ */
+MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
+
+/**
+ * Check if a Fiber is alive
+ *
+ * Implemented in mruby-fiber
+ */
+MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
+
+/**
+ * FiberError reference
+ *
+ * Implemented in mruby-fiber
+ */
+#define E_FIBER_ERROR mrb_exc_get_id(mrb, MRB_ERROR_SYM(FiberError))
+MRB_API void mrb_stack_extend(mrb_state*, mrb_int);
/* memory pool implementation */
typedef struct mrb_pool mrb_pool;
-struct mrb_pool* mrb_pool_open(mrb_state*);
-void mrb_pool_close(struct mrb_pool*);
-void* mrb_pool_alloc(struct mrb_pool*, size_t);
-void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen);
-mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t);
-void* mrb_alloca(mrb_state *mrb, size_t);
+MRB_API struct mrb_pool* mrb_pool_open(mrb_state*);
+MRB_API void mrb_pool_close(struct mrb_pool*);
+MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t);
+MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen);
+MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t);
+/* temporary memory allocation, only effective while GC arena is kept */
+MRB_API void* mrb_alloca(mrb_state *mrb, size_t);
-void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
+MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
-#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
+MRB_API void mrb_show_version(mrb_state *mrb);
+MRB_API void mrb_show_copyright(mrb_state *mrb);
-#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_value mrb_format(mrb_state *mrb, const char *format, ...);
+#ifdef MRB_PRESYM_SCANNING
+# include <mruby/presym/scanning.h>
+#endif
-#if defined(__cplusplus)
-} /* extern "C" { */
+#if 0
+/* memcpy and memset does not work with gdb reverse-next on my box */
+/* use naive memcpy and memset instead */
+#undef memcpy
+#undef memset
+static void*
+mrbmemcpy(void *dst, const void *src, size_t n)
+{
+ char *d = (char*)dst;
+ const char *s = (const char*)src;
+ while (n--)
+ *d++ = *s++;
+ return d;
+}
+#define memcpy(a,b,c) mrbmemcpy(a,b,c)
+
+static void*
+mrbmemset(void *s, int c, size_t n)
+{
+ char *t = (char*)s;
+ while (n--)
+ *t++ = c;
+ return s;
+}
+#define memset(a,b,c) mrbmemset(a,b,c)
#endif
+MRB_END_DECL
+
#endif /* MRUBY_H */
diff --git a/include/mruby/array.h b/include/mruby/array.h
index 9db51aa5b..8bb652472 100644
--- a/include/mruby/array.h
+++ b/include/mruby/array.h
@@ -1,5 +1,5 @@
-/*
-** mruby/array.h - Array class
+/**
+** @file mruby/array.h - Array class
**
** See Copyright Notice in mruby.h
*/
@@ -7,65 +7,298 @@
#ifndef MRUBY_ARRAY_H
#define MRUBY_ARRAY_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+
+/*
+ * Array class
+ */
+MRB_BEGIN_DECL
typedef struct mrb_shared_array {
int refcnt;
- mrb_int len;
+ mrb_ssize len;
mrb_value *ptr;
} mrb_shared_array;
+#if defined(MRB_32BIT) && defined(MRB_NO_BOXING) && !defined(MRB_USE_FLOAT32) && !defined(MRB_ARY_NO_EMBED)
+# define MRB_ARY_NO_EMBED
+#endif
+
+#ifdef MRB_ARY_NO_EMBED
+# define MRB_ARY_EMBED_LEN_MAX 0
+#else
+# define MRB_ARY_EMBED_LEN_MAX ((mrb_int)(sizeof(void*)*3/sizeof(mrb_value)))
+mrb_static_assert(MRB_ARY_EMBED_LEN_MAX > 0, "MRB_ARY_EMBED_LEN_MAX > 0");
+#endif
+
struct RArray {
MRB_OBJECT_HEADER;
- mrb_int len;
union {
- mrb_int capa;
- mrb_shared_array *shared;
- } aux;
- mrb_value *ptr;
+ struct {
+ mrb_ssize len;
+ union {
+ mrb_ssize capa;
+ mrb_shared_array *shared;
+ } aux;
+ mrb_value *ptr;
+ } heap;
+#ifndef MRB_ARY_NO_EMBED
+ mrb_value ary[MRB_ARY_EMBED_LEN_MAX];
+#endif
+ } as;
};
#define mrb_ary_ptr(v) ((struct RArray*)(mrb_ptr(v)))
#define mrb_ary_value(p) mrb_obj_value((void*)(p))
#define RARRAY(v) ((struct RArray*)(mrb_ptr(v)))
-#define RARRAY_LEN(a) (RARRAY(a)->len)
-#define RARRAY_PTR(a) (RARRAY(a)->ptr)
+#ifdef MRB_ARY_NO_EMBED
+#define ARY_EMBED_P(a) 0
+#define ARY_UNSET_EMBED_FLAG(a) (void)0
+#define ARY_EMBED_LEN(a) 0
+#define ARY_SET_EMBED_LEN(a,len) (void)0
+#define ARY_EMBED_PTR(a) 0
+#else
+#define MRB_ARY_EMBED_MASK 7
+#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED_MASK)
+#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK))
+#define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1))
+#define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1))
+#define ARY_EMBED_PTR(a) ((a)->as.ary)
+#endif
+
+#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(mrb_int)(a)->as.heap.len)
+#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
+#define RARRAY_LEN(a) ARY_LEN(RARRAY(a))
+#define RARRAY_PTR(a) ARY_PTR(RARRAY(a))
+#define ARY_SET_LEN(a,n) do {\
+ if (ARY_EMBED_P(a)) {\
+ mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \
+ ARY_SET_EMBED_LEN(a,n);\
+ }\
+ else\
+ (a)->as.heap.len = (n);\
+} while (0)
+#define ARY_CAPA(a) (ARY_EMBED_P(a)?MRB_ARY_EMBED_LEN_MAX:(a)->as.heap.aux.capa)
#define MRB_ARY_SHARED 256
+#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
+#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
+#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED)
-void mrb_ary_modify(mrb_state*, struct RArray*);
void mrb_ary_decref(mrb_state*, mrb_shared_array*);
-mrb_value mrb_ary_new_capa(mrb_state*, mrb_int);
-mrb_value mrb_ary_new(mrb_state *mrb);
-mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals);
-mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr);
-void mrb_ary_concat(mrb_state*, mrb_value, mrb_value);
-mrb_value mrb_ary_splat(mrb_state*, mrb_value);
-void mrb_ary_push(mrb_state*, mrb_value, mrb_value);
-mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary);
-mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n);
-void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val);
-void mrb_ary_replace(mrb_state *mrb, mrb_value a, mrb_value b);
-mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
-mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item);
-mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
-mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self);
-mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self);
-mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep);
-mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int len);
-
-static inline mrb_int
-mrb_ary_len(mrb_state *mrb, mrb_value ary)
-{
- (void)mrb;
- mrb_assert(mrb_array_p(ary));
- return RARRAY_LEN(ary);
-}
-
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_API void mrb_ary_modify(mrb_state*, struct RArray*);
+MRB_API mrb_value mrb_ary_new_capa(mrb_state*, mrb_int);
+
+/*
+ * Initializes a new array.
+ *
+ * Equivalent to:
+ *
+ * Array.new
+ *
+ * @param mrb The mruby state reference.
+ * @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 number 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);
+
+/*
+ * 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.
+ *
+ * Equivalent to:
+ *
+ * ary << value
+ *
+ * @param mrb The mruby state reference.
+ * @param ary The array in which the value will be pushed
+ * @param value The value to be pushed into array
+ */
+MRB_API void mrb_ary_push(mrb_state *mrb, mrb_value array, mrb_value value);
+
+/*
+ * Pops the last element from the array.
+ *
+ * Equivalent to:
+ *
+ * ary.pop
+ *
+ * @param mrb The mruby state reference.
+ * @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);
+
+/*
+ * Sets a value on an array at the given index
+ *
+ * Equivalent to:
+ *
+ * ary[n] = val
+ *
+ * @param mrb The mruby state reference.
+ * @param ary The target array.
+ * @param n The array index being referenced.
+ * @param val The value being set.
+ */
+MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val);
+
+/*
+ * 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);
+
+/*
+ * Unshift an element into the 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);
+
+/*
+ * Get nth element in the array
+ *
+ * Equivalent to:
+ *
+ * ary[offset]
+ *
+ * @param ary The target array.
+ * @param offset The element position (negative counts from the tail).
+ */
+MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
+#define mrb_ary_ref(mrb, ary, n) mrb_ary_entry(ary, n)
+
+/*
+ * Replace subsequence of an array.
+ *
+ * Equivalent to:
+ *
+ * ary[head, len] = rpl
+ *
+ * @param mrb The mruby state reference.
+ * @param self The array from which the value will be partiality replaced.
+ * @param head Beginning position of a replacement subsequence.
+ * @param len Length of a replacement subsequence.
+ * @param rpl The array of replacement elements.
+ * It is possible to pass `mrb_undef_value()` instead of an empty array.
+ * @return The receiver array.
+ */
+MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value self, mrb_int head, mrb_int len, mrb_value rpl);
+
+/*
+ * 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 the 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 separator, can be NULL
+ */
+MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep);
+
+/*
+ * 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);
+
+/* helper functions */
+mrb_value mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len);
+
+MRB_END_DECL
#endif /* MRUBY_ARRAY_H */
diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h
index ab5807b08..cbf7953ed 100644
--- a/include/mruby/boxing_nan.h
+++ b/include/mruby/boxing_nan.h
@@ -1,5 +1,5 @@
-/*
-** mruby/boxing_nan.h - nan boxing mrb_value definition
+/**
+** @file mruby/boxing_nan.h - nan boxing mrb_value definition
**
** See Copyright Notice in mruby.h
*/
@@ -7,8 +7,12 @@
#ifndef MRUBY_BOXING_NAN_H
#define MRUBY_BOXING_NAN_H
-#ifdef MRB_USE_FLOAT
-# error ---->> MRB_NAN_BOXING and MRB_USE_FLOAT conflict <<----
+#ifdef MRB_USE_FLOAT32
+# error ---->> MRB_NAN_BOXING and MRB_USE_FLOAT32 conflict <<----
+#endif
+
+#ifdef MRB_NO_FLOAT
+# error ---->> MRB_NAN_BOXING and MRB_NO_FLOAT conflict <<----
#endif
#ifdef MRB_INT64
@@ -16,79 +20,150 @@
#endif
#define MRB_FIXNUM_SHIFT 0
-#define MRB_TT_HAS_BASIC MRB_TT_OBJECT
+#define MRB_SYMBOL_SHIFT 0
+#define MRB_FIXNUM_MIN INT32_MIN
+#define MRB_FIXNUM_MAX INT32_MAX
-#ifdef MRB_ENDIAN_BIG
-#define MRB_ENDIAN_LOHI(a,b) a b
-#else
-#define MRB_ENDIAN_LOHI(a,b) b a
+enum mrb_nanbox_tt_inline {
+ MRB_NANBOX_TT_POINTER = 1,
+ MRB_NANBOX_TT_INTEGER,
+ MRB_NANBOX_TT_SYMBOL,
+ MRB_NANBOX_TT_MISC,
+#ifndef MRB_NO_FLOAT
+ MRB_NANBOX_TT_FLOAT,
#endif
+};
/* value representation by nan-boxing:
* float : FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
- * object: 111111111111TTTT TTPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP
- * int : 1111111111110001 0000000000000000 IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII
- * sym : 1111111111110001 0100000000000000 SSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSS
- * In order to get enough bit size to save TT, all pointers are shifted 2 bits
- * in the right direction. Also, TTTTTT is the mrb_vtype + 1;
+ * object: 1111111111110001 PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP
+ * int : 1111111111110010 0000000000000000 IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII
+ * sym : 1111111111110011 0100000000000000 SSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSS
+ * misc : 1111111111110100 0100000000000000 0000000000000000 TTTTTT000000MMMM
*/
typedef struct mrb_value {
+ uint64_t u;
+} mrb_value;
+
+union mrb_value_ {
+ mrb_float f;
+ uint64_t u;
+#ifdef MRB_64BIT
+ void *p;
+#endif
+ mrb_value value;
+};
+
+mrb_static_assert1(sizeof(mrb_value) == sizeof(union mrb_value_));
+
+static inline union mrb_value_
+mrb_val_union(mrb_value v)
+{
+ union mrb_value_ x;
+ x.u = v.u;
+ return x;
+}
+
+static inline mrb_float
+mrb_float(mrb_value v)
+{
union {
mrb_float f;
- union {
- void *p;
- struct {
- MRB_ENDIAN_LOHI(
- uint32_t ttt;
- ,union {
- mrb_int i;
- mrb_sym sym;
- };
- )
- };
- } value;
- };
-} mrb_value;
+ uint64_t u;
+ } x;
+ x.u = v.u;
+ return x.f;
+}
+
+#define mrb_tt_(o) ((enum mrb_nanbox_tt_inline)((o).u >> 48)&0xf)
+
+MRB_INLINE enum mrb_vtype
+mrb_type(mrb_value o)
+{
+ switch (mrb_tt_(o)) {
+ case MRB_NANBOX_TT_POINTER:
+ return RBASIC(o)->tt;
+ case MRB_NANBOX_TT_INTEGER:
+ return MRB_TT_INTEGER;
+ case MRB_NANBOX_TT_SYMBOL:
+ return MRB_TT_SYMBOL;
+ case MRB_NANBOX_TT_MISC:
+ return (enum mrb_vtype)(o.u >> 10) & 0x3f;
+#ifndef MRB_NO_FLOAT
+ default:
+ return MRB_TT_FLOAT;
+#endif
+ }
+ return MRB_TT_UNDEF;
+}
+
+#define mrb_symbol(o) ((mrb_sym)((o).u & 0x3fffffff))
-#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f)
+#ifdef MRB_INT64
+#define mrb_fixnum(o) ((mrb_int)((o).u & 0xffffffffffffL))
+#define mrb_integer(o) ((mrb_tt(o)==MRB_NANBOX_TT_POINTER)?(((struct RInteger*)mrb_ptr(o))->i):mrb_fixnum(o)))
+#else /* MRB_INT32 */
+#define mrb_fixnum(o) ((mrb_int)((o).u & 0xffffffff))
+#define mrb_integer(o) mrb_fixnum(o)
+#endif
-#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_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2))
-#define mrb_float(o) (o).f
+#ifdef MRB_64BIT
+#define mrb_ptr(o) ((void*)(((uintptr_t)(o).u) & 0xffffffffffff))
+#else
+#define mrb_ptr(o) ((void*)(((uintptr_t)(o).u) & 0xffffffff))
+#endif
#define mrb_cptr(o) mrb_ptr(o)
-#define mrb_fixnum(o) (o).value.i
-#define mrb_symbol(o) (o).value.sym
-
-#define BOXNAN_SET_VALUE(o, tt, attr, v) do {\
- (o).value.ttt = (0xfff00000|(((tt)+1)<<14));\
- 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;\
- }\
+
+#define NANBOX_SET_VALUE(o, tt, attr, v) do { \
+ union mrb_value_ mrb_value_union_variable; \
+ mrb_value_union_variable.attr = (v);\
+ mrb_value_union_variable.ttt = 0xfff00000 | (((tt)+1)<<14);\
+ o = mrb_value_union_variable.value;\
+} while (0)
+
+#ifdef MRB_64BIT
+#define NANBOX_SET_OBJ_VALUE(o, tt, v) do {\
+ union mrb_value_ mrb_value_union_variable;\
+ mrb_value_union_variable.p = (void*)((uintptr_t)(v)>>2);\
+ mrb_value_union_variable.ttt = (0xfff00000|(((tt)+1)<<14)|NANBOX_SHIFT_LONG_POINTER(v));\
+ o = mrb_value_union_variable.value;\
} while (0)
+#else
+#define NANBOX_SET_OBJ_VALUE(o, tt, v) NANBOX_SET_VALUE(o, tt, i, (uint32_t)v)
+#endif
#define SET_FLOAT_VALUE(mrb,r,v) do { \
- if (v != v) { \
- (r).value.ttt = 0x7ff80000; \
- (r).value.i = 0; \
- } else { \
- (r).f = v; \
- }} while(0)
-
-#define SET_NIL_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_FALSE_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_TRUE_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#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_PROC_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_PROC, value.p, v)
-#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_VALUE(r, MRB_TT_CPTR, value.p, v)
-#define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
+ union mrb_value_ mrb_value_union_variable; \
+ if ((v) != (v)) { /* NaN */ \
+ mrb_value_union_variable.u = 0x7ff8000000000000UL; \
+ } \
+ else { \
+ mrb_value_union_variable.f = (v); \
+ } \
+ r = mrb_value_union_variable.value; \
+} while(0)
+
+#define NANBOX_SET_MISC_VALUE(o, tt, attr, v) do { \
+ union mrb_value_ mrb_value_union_variable; \
+ mrb_value_union_variable.attr = (v);\
+ mrb_value_union_variable.ttt = 0xfff00000 | (((tt)+1)<<14);\
+ o = mrb_value_union_variable.value;\
+} while (0)
+
+#define SET_NIL_VALUE(r) NANBOX_SET_VALUE(r, MRB_TT_FALSE, i, 0)
+#define SET_FALSE_VALUE(r) NANBOX_SET_VALUE(r, MRB_TT_FALSE, i, 1)
+#define SET_TRUE_VALUE(r) NANBOX_SET_VALUE(r, MRB_TT_TRUE, i, 1)
+#define SET_BOOL_VALUE(r,b) NANBOX_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, i, 1)
+#define SET_INT_VALUE(mrb, r,n) NANBOX_SET_VALUE(r, MRB_TT_INTEGER, i, (uint32_t)(n))
+#define SET_FIXNUM_VALUE(r,n) NANBOX_SET_VALUE(r, MRB_TT_INTEGER, i, (uint32_t)(n))
+#define SET_SYM_VALUE(r,v) NANBOX_SET_VALUE(r, MRB_TT_SYMBOL, i, (uint32_t)(v))
+#define SET_OBJ_VALUE(r,v) NANBOX_SET_OBJ_VALUE(r, (((struct RObject*)(v))->tt), (v))
+#ifdef MRB_64BIT
+MRB_API mrb_value mrb_nan_boxing_cptr_value(struct mrb_state*, void*);
+#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_nan_boxing_cptr_value(mrb, v))
+#else
+#define SET_CPTR_VALUE(mrb,r,v) NANBOX_SET_VALUE(r, MRB_TT_CPTR, p, v)
+#endif
+#define SET_UNDEF_VALUE(r) NANBOX_SET_VALUE(r, MRB_TT_UNDEF, i, 0)
#endif /* MRUBY_BOXING_NAN_H */
diff --git a/include/mruby/boxing_no.h b/include/mruby/boxing_no.h
index e5aec5461..84908a0d8 100644
--- a/include/mruby/boxing_no.h
+++ b/include/mruby/boxing_no.h
@@ -1,5 +1,5 @@
-/*
-** mruby/boxing_no.h - unboxed mrb_value definition
+/**
+** @file mruby/boxing_no.h - unboxed mrb_value definition
**
** See Copyright Notice in mruby.h
*/
@@ -8,24 +8,31 @@
#define MRUBY_BOXING_NO_H
#define MRB_FIXNUM_SHIFT 0
-#define MRB_TT_HAS_BASIC MRB_TT_OBJECT
+#define MRB_SYMBOL_SHIFT 0
+#define MRB_FIXNUM_MIN MRB_INT_MIN
+#define MRB_FIXNUM_MAX MRB_INT_MAX
+
+union mrb_value_union {
+#ifndef MRB_NO_FLOAT
+ mrb_float f;
+#endif
+ void *p;
+ mrb_int i;
+ mrb_sym sym;
+};
typedef struct mrb_value {
- union {
- mrb_float f;
- void *p;
- mrb_int i;
- mrb_sym sym;
- } value;
+ union mrb_value_union value;
enum mrb_vtype tt;
} mrb_value;
-#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f)
-
#define mrb_ptr(o) (o).value.p
#define mrb_cptr(o) mrb_ptr(o)
+#ifndef MRB_NO_FLOAT
#define mrb_float(o) (o).value.f
+#endif
#define mrb_fixnum(o) (o).value.i
+#define mrb_integer(o) mrb_fixnum(o)
#define mrb_symbol(o) (o).value.sym
#define mrb_type(o) (o).tt
@@ -38,11 +45,13 @@ typedef struct mrb_value {
#define SET_FALSE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
#define SET_TRUE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
#define SET_BOOL_VALUE(r,b) BOXNIX_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
-#define SET_INT_VALUE(r,n) BOXNIX_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
+#define SET_INT_VALUE(mrb,r,n) BOXNIX_SET_VALUE(r, MRB_TT_INTEGER, value.i, (n))
+#define SET_FIXNUM_VALUE(r,n) BOXNIX_SET_VALUE(r, MRB_TT_INTEGER, value.i, (n))
+#ifndef MRB_NO_FLOAT
#define SET_FLOAT_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v))
+#endif
#define SET_SYM_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
#define SET_OBJ_VALUE(r,v) BOXNIX_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#define SET_PROC_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_PROC, value.p, v)
#define SET_CPTR_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_CPTR, value.p, v)
#define SET_UNDEF_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h
index 92e6ae6de..89c6f6f2d 100644
--- a/include/mruby/boxing_word.h
+++ b/include/mruby/boxing_word.h
@@ -1,5 +1,5 @@
-/*
-** mruby/boxing_word.h - word boxing mrb_value definition
+/**
+** @file mruby/boxing_word.h - word boxing mrb_value definition
**
** See Copyright Notice in mruby.h
*/
@@ -7,113 +7,226 @@
#ifndef MRUBY_BOXING_WORD_H
#define MRUBY_BOXING_WORD_H
-#if defined(MRB_INT16)
-# error MRB_INT16 is too small for MRB_WORD_BOXING.
+#if defined(MRB_32BIT) && !defined(MRB_USE_FLOAT32)
+# define MRB_WORDBOX_NO_FLOAT_TRUNCATE
#endif
+#if !defined(MRB_NO_FLOAT) && defined(MRB_WORDBOX_NO_FLOAT_TRUNCATE)
struct RFloat {
MRB_OBJECT_HEADER;
mrb_float f;
};
+#endif
-struct RCptr {
+struct RInteger {
MRB_OBJECT_HEADER;
- void *p;
+ mrb_int i;
};
-#define MRB_FIXNUM_SHIFT 1
-#define MRB_TT_HAS_BASIC MRB_TT_FLOAT
-
enum mrb_special_consts {
- MRB_Qnil = 0,
- MRB_Qfalse = 2,
- MRB_Qtrue = 4,
- MRB_Qundef = 6,
+ MRB_Qnil = 0,
+ MRB_Qfalse = 4,
+ MRB_Qtrue = 12,
+ MRB_Qundef = 20,
};
-#define MRB_FIXNUM_FLAG 0x01
-#define MRB_SYMBOL_FLAG 0x0e
-#define MRB_SPECIAL_SHIFT 8
-
-typedef union mrb_value {
- union {
- void *p;
- struct {
- unsigned int i_flag : MRB_FIXNUM_SHIFT;
- mrb_int i : (MRB_INT_BIT - MRB_FIXNUM_SHIFT);
- };
- struct {
- unsigned int sym_flag : MRB_SPECIAL_SHIFT;
- int sym : (sizeof(mrb_sym) * CHAR_BIT);
- };
- struct RBasic *bp;
- struct RFloat *fp;
- struct RCptr *vp;
- } value;
- unsigned long w;
-} mrb_value;
+#if defined(MRB_64BIT) && defined(MRB_INT32)
+#define MRB_FIXNUM_SHIFT 0
+#else
+#define MRB_FIXNUM_SHIFT WORDBOX_FIXNUM_SHIFT
+#endif
+#define MRB_SYMBOL_SHIFT WORDBOX_SYMBOL_SHIFT
+
+#if defined(MRB_64BIT) && defined(MRB_INT64)
+# define MRB_FIXNUM_MIN (INT64_MIN>>MRB_FIXNUM_SHIFT)
+# define MRB_FIXNUM_MAX (INT64_MAX>>MRB_FIXNUM_SHIFT)
+#else
+# define MRB_FIXNUM_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT)
+# define MRB_FIXNUM_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT)
+#endif
-mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*);
-mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float);
-mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float);
+#define WORDBOX_FIXNUM_BIT_POS 1
+#define WORDBOX_FIXNUM_SHIFT WORDBOX_FIXNUM_BIT_POS
+#define WORDBOX_FIXNUM_FLAG (1 << (WORDBOX_FIXNUM_BIT_POS - 1))
+#define WORDBOX_FIXNUM_MASK ((1 << WORDBOX_FIXNUM_BIT_POS) - 1)
+
+#if defined(MRB_WORDBOX_NO_FLOAT_TRUNCATE)
+/* floats are allocated in heaps */
+#define WORDBOX_SYMBOL_BIT_POS 2
+#define WORDBOX_SYMBOL_SHIFT WORDBOX_SYMBOL_BIT_POS
+#define WORDBOX_SYMBOL_FLAG (1 << (WORDBOX_SYMBOL_BIT_POS - 1))
+#define WORDBOX_SYMBOL_MASK ((1 << WORDBOX_SYMBOL_BIT_POS) - 1)
+#else
+#define WORDBOX_FLOAT_FLAG 2
+#define WORDBOX_FLOAT_MASK 3
+#if defined(MRB_64BIT)
+#define WORDBOX_SYMBOL_SHIFT 32
+#else /* MRB_32BIT */
+#define WORDBOX_SYMBOL_SHIFT 5
+#endif
+#define WORDBOX_SYMBOL_FLAG 0x1c
+#define WORDBOX_SYMBOL_MASK 0x1f
+#endif
-#define mrb_float_pool(mrb,f) mrb_word_boxing_float_pool(mrb,f)
+#define WORDBOX_IMMEDIATE_MASK 0x07
-#define mrb_ptr(o) (o).value.p
-#define mrb_cptr(o) (o).value.vp->p
-#define mrb_float(o) (o).value.fp->f
-#define mrb_fixnum(o) (o).value.i
-#define mrb_symbol(o) (o).value.sym
+#define WORDBOX_SET_SHIFT_VALUE(o,n,v) \
+ ((o).w = (((uintptr_t)(v)) << WORDBOX_##n##_SHIFT) | WORDBOX_##n##_FLAG)
+#define WORDBOX_SHIFT_VALUE_P(o,n) \
+ (((o).w & WORDBOX_##n##_MASK) == WORDBOX_##n##_FLAG)
+#define WORDBOX_OBJ_TYPE_P(o,n) \
+ (!mrb_immediate_p(o) && mrb_val_union(o).bp->tt == MRB_TT_##n)
-static inline enum mrb_vtype
-mrb_type(mrb_value o)
+/*
+ * mrb_value representation:
+ *
+ * 64bit word with inline float:
+ * nil : ...0000 0000 (all bits are 0)
+ * false : ...0000 0100 (mrb_fixnum(v) != 0)
+ * true : ...0000 1100
+ * undef : ...0001 0100
+ * symbol: ...0001 1100 (use only upper 32-bit as symbol value with MRB_64BIT)
+ * fixnum: ...IIII III1
+ * float : ...FFFF FF10 (51 bit significands; require MRB_64BIT)
+ * object: ...PPPP P000
+ *
+ * 32bit word with inline float:
+ * nil : ...0000 0000 (all bits are 0)
+ * false : ...0000 0100 (mrb_fixnum(v) != 0)
+ * true : ...0000 1100
+ * undef : ...0001 0100
+ * symbol: ...SSS1 1100 (use only upper 32-bit as symbol value with MRB_64BIT)
+ * symbol: ...SSS1 0100 (symbol occupies 20bits)
+ * fixnum: ...IIII III1
+ * float : ...FFFF FF10 (22 bit significands; require MRB_64BIT)
+ * object: ...PPPP P000
+ *
+ * and word boxing without inline float:
+ * nil : ...0000 0000 (all bits are 0)
+ * false : ...0000 0100 (mrb_fixnum(v) != 0)
+ * true : ...0000 1100
+ * undef : ...0001 0100
+ * fixnum: ...IIII III1
+ * symbol: ...SSSS SS10
+ * object: ...PPPP P000 (any bits are 1)
+ */
+typedef struct mrb_value {
+ uintptr_t w;
+} mrb_value;
+
+union mrb_value_ {
+ void *p;
+ struct RBasic *bp;
+#ifndef MRB_NO_FLOAT
+#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE
+ mrb_float f;
+#else
+ struct RFloat *fp;
+#endif
+#endif
+ struct RInteger *ip;
+ struct RCptr *vp;
+ uintptr_t w;
+ mrb_value value;
+};
+
+mrb_static_assert1(sizeof(mrb_value) == sizeof(union mrb_value_));
+
+static inline union mrb_value_
+mrb_val_union(mrb_value v)
{
- switch (o.w) {
- case MRB_Qfalse:
- case MRB_Qnil:
- return MRB_TT_FALSE;
- case MRB_Qtrue:
- return MRB_TT_TRUE;
- case MRB_Qundef:
- return MRB_TT_UNDEF;
- }
- if (o.value.i_flag == MRB_FIXNUM_FLAG) {
- return MRB_TT_FIXNUM;
- }
- if (o.value.sym_flag == MRB_SYMBOL_FLAG) {
- return MRB_TT_SYMBOL;
- }
- return o.value.bp->tt;
+ union mrb_value_ x;
+ x.value = v;
+ return x;
+}
+
+MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*);
+#ifndef MRB_NO_FLOAT
+MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float);
+#endif
+MRB_API mrb_value mrb_word_boxing_int_value(struct mrb_state*, mrb_int);
+
+#define mrb_immediate_p(o) ((o).w & WORDBOX_IMMEDIATE_MASK || (o).w == MRB_Qnil)
+
+#define mrb_ptr(o) mrb_val_union(o).p
+#define mrb_cptr(o) mrb_val_union(o).vp->p
+#ifndef MRB_NO_FLOAT
+#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE
+MRB_API mrb_float mrb_word_boxing_value_float(mrb_value v);
+#define mrb_float(o) mrb_word_boxing_value_float(o)
+#else
+#define mrb_float(o) mrb_val_union(o).fp->f
+#endif
+#endif
+#define mrb_fixnum(o) (mrb_int)(((intptr_t)(o).w) >> WORDBOX_FIXNUM_SHIFT)
+MRB_INLINE mrb_int
+mrb_integer_func(mrb_value o) {
+ if (mrb_immediate_p(o)) return mrb_fixnum(o);
+ return mrb_val_union(o).ip->i;
}
+#define mrb_integer(o) mrb_integer_func(o)
+#define mrb_symbol(o) (mrb_sym)(((o).w) >> WORDBOX_SYMBOL_SHIFT)
+#define mrb_bool(o) (((o).w & ~(uintptr_t)MRB_Qfalse) != 0)
-#define mrb_bool(o) ((o).w != MRB_Qnil && (o).w != MRB_Qfalse)
-#define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG)
+#define mrb_fixnum_p(o) WORDBOX_SHIFT_VALUE_P(o, FIXNUM)
+#define mrb_integer_p(o) (WORDBOX_SHIFT_VALUE_P(o, FIXNUM)||WORDBOX_OBJ_TYPE_P(o, INTEGER))
+#define mrb_symbol_p(o) WORDBOX_SHIFT_VALUE_P(o, SYMBOL)
#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 {\
- (o).w = 0;\
- (o).attr = (v);\
- 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; break;\
- case MRB_TT_SYMBOL: (o).value.sym_flag = MRB_SYMBOL_FLAG; break;\
- default: if ((o).value.bp) (o).value.bp->tt = ttt; break;\
- }\
-} while (0)
-
-#define SET_FLOAT_VALUE(mrb,r,v) r = mrb_word_boxing_float_value(mrb, v)
-#define SET_CPTR_VALUE(mrb,r,v) r = mrb_word_boxing_cptr_value(mrb, v)
-#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
-#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
-#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#define SET_PROC_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_PROC, value.p, v)
-#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0)
+#define mrb_false_p(o) ((o).w == MRB_Qfalse)
+#define mrb_true_p(o) ((o).w == MRB_Qtrue)
+#ifndef MRB_NO_FLOAT
+#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE
+#define mrb_float_p(o) WORDBOX_SHIFT_VALUE_P(o, FLOAT)
+#else
+#define mrb_float_p(o) WORDBOX_OBJ_TYPE_P(o, FLOAT)
+#endif
+#endif
+#define mrb_array_p(o) WORDBOX_OBJ_TYPE_P(o, ARRAY)
+#define mrb_string_p(o) WORDBOX_OBJ_TYPE_P(o, STRING)
+#define mrb_hash_p(o) WORDBOX_OBJ_TYPE_P(o, HASH)
+#define mrb_cptr_p(o) WORDBOX_OBJ_TYPE_P(o, CPTR)
+#define mrb_exception_p(o) WORDBOX_OBJ_TYPE_P(o, EXCEPTION)
+#define mrb_free_p(o) WORDBOX_OBJ_TYPE_P(o, FREE)
+#define mrb_object_p(o) WORDBOX_OBJ_TYPE_P(o, OBJECT)
+#define mrb_class_p(o) WORDBOX_OBJ_TYPE_P(o, CLASS)
+#define mrb_module_p(o) WORDBOX_OBJ_TYPE_P(o, MODULE)
+#define mrb_iclass_p(o) WORDBOX_OBJ_TYPE_P(o, ICLASS)
+#define mrb_sclass_p(o) WORDBOX_OBJ_TYPE_P(o, SCLASS)
+#define mrb_proc_p(o) WORDBOX_OBJ_TYPE_P(o, PROC)
+#define mrb_range_p(o) WORDBOX_OBJ_TYPE_P(o, RANGE)
+#define mrb_env_p(o) WORDBOX_OBJ_TYPE_P(o, ENV)
+#define mrb_data_p(o) WORDBOX_OBJ_TYPE_P(o, DATA)
+#define mrb_fiber_p(o) WORDBOX_OBJ_TYPE_P(o, FIBER)
+#define mrb_istruct_p(o) WORDBOX_OBJ_TYPE_P(o, ISTRUCT)
+#define mrb_break_p(o) WORDBOX_OBJ_TYPE_P(o, BREAK)
+
+#ifndef MRB_NO_FLOAT
+#define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v))
+#endif
+#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v))
+#define SET_UNDEF_VALUE(r) ((r).w = MRB_Qundef)
+#define SET_NIL_VALUE(r) ((r).w = MRB_Qnil)
+#define SET_FALSE_VALUE(r) ((r).w = MRB_Qfalse)
+#define SET_TRUE_VALUE(r) ((r).w = MRB_Qtrue)
+#define SET_BOOL_VALUE(r,b) ((b) ? SET_TRUE_VALUE(r) : SET_FALSE_VALUE(r))
+#define SET_INT_VALUE(mrb,r,n) ((r) = mrb_word_boxing_int_value(mrb, n))
+#define SET_FIXNUM_VALUE(r,n) WORDBOX_SET_SHIFT_VALUE(r, FIXNUM, n)
+#define SET_SYM_VALUE(r,n) WORDBOX_SET_SHIFT_VALUE(r, SYMBOL, n)
+#define SET_OBJ_VALUE(r,v) ((r).w = (uintptr_t)(v))
+
+MRB_INLINE enum mrb_vtype
+mrb_type(mrb_value o)
+{
+ return !mrb_bool(o) ? MRB_TT_FALSE :
+ mrb_true_p(o) ? MRB_TT_TRUE :
+ mrb_fixnum_p(o) ? MRB_TT_INTEGER :
+ mrb_symbol_p(o) ? MRB_TT_SYMBOL :
+ mrb_undef_p(o) ? MRB_TT_UNDEF :
+#ifndef MRB_NO_FLOAT
+ mrb_float_p(o) ? MRB_TT_FLOAT :
+#endif
+ mrb_val_union(o).bp->tt;
+}
#endif /* MRUBY_BOXING_WORD_H */
diff --git a/include/mruby/class.h b/include/mruby/class.h
index f116f5b6d..b97bc3991 100644
--- a/include/mruby/class.h
+++ b/include/mruby/class.h
@@ -1,5 +1,5 @@
-/*
-** mruby/class.h - Class class
+/**
+** @file mruby/class.h - Class class
**
** See Copyright Notice in mruby.h
*/
@@ -7,23 +7,23 @@
#ifndef MRUBY_CLASS_H
#define MRUBY_CLASS_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+
+/**
+ * Class class
+ */
+MRB_BEGIN_DECL
struct RClass {
MRB_OBJECT_HEADER;
struct iv_tbl *iv;
- struct kh_mt *mt;
+ struct mt_tbl *mt;
struct RClass *super;
};
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
-#define RCLASS_SUPER(v) (((struct RClass*)(mrb_ptr(v)))->super)
-#define RCLASS_IV_TBL(v) (((struct RClass*)(mrb_ptr(v)))->iv)
-#define RCLASS_M_TBL(v) (((struct RClass*)(mrb_ptr(v)))->mt)
-static inline struct RClass*
+MRB_INLINE struct RClass*
mrb_class(mrb_state *mrb, mrb_value v)
{
switch (mrb_type(v)) {
@@ -35,10 +35,12 @@ mrb_class(mrb_state *mrb, mrb_value v)
return mrb->true_class;
case MRB_TT_SYMBOL:
return mrb->symbol_class;
- case MRB_TT_FIXNUM:
- return mrb->fixnum_class;
+ case MRB_TT_INTEGER:
+ return mrb->integer_class;
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
return mrb->float_class;
+#endif
case MRB_TT_CPTR:
return mrb->object_class;
case MRB_TT_ENV:
@@ -48,30 +50,59 @@ mrb_class(mrb_state *mrb, mrb_value v)
}
}
-#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~0xff) | (char)tt)
-#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & 0xff)
+/* flags:
+ 20: frozen
+ 19: is_prepended
+ 18: is_origin
+ 17: is_inherited (used by method cache)
+ 16: unused
+ 0-15: instance type
+*/
+#define MRB_FL_CLASS_IS_PREPENDED (1 << 19)
+#define MRB_FL_CLASS_IS_ORIGIN (1 << 18)
+#define MRB_CLASS_ORIGIN(c) do {\
+ if ((c)->flags & MRB_FL_CLASS_IS_PREPENDED) {\
+ (c) = (c)->super;\
+ while (!((c)->flags & MRB_FL_CLASS_IS_ORIGIN)) {\
+ (c) = (c)->super;\
+ }\
+ }\
+} while (0)
+#define MRB_FL_CLASS_IS_INHERITED (1 << 17)
+#define MRB_INSTANCE_TT_MASK (0xFF)
+#define MRB_SET_INSTANCE_TT(c, tt) ((c)->flags = (((c)->flags & ~MRB_INSTANCE_TT_MASK) | (char)(tt)))
+#define MRB_INSTANCE_TT(c) (enum mrb_vtype)((c)->flags & MRB_INSTANCE_TT_MASK)
-struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*);
-struct RClass* mrb_define_module_id(mrb_state*, mrb_sym);
struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym);
struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym);
-void mrb_define_method_vm(mrb_state*, struct RClass*, mrb_sym, mrb_value);
-void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, struct RProc *);
-void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec);
-void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b);
+MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t);
+MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b);
+MRB_API void mrb_remove_method(mrb_state *mrb, struct RClass *c, mrb_sym sym);
-struct RClass *mrb_class_outer_module(mrb_state*, struct RClass *);
-struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
-struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
+MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
+MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
-struct RClass* mrb_class_real(struct RClass* cl);
+MRB_API struct RClass* mrb_class_real(struct RClass* cl);
+mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv);
+void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym);
+mrb_bool mrb_const_name_p(mrb_state*, const char*, mrb_int);
+mrb_value mrb_class_find_path(mrb_state*, struct RClass*);
+mrb_value mrb_mod_to_s(mrb_state*, mrb_value);
void mrb_gc_mark_mt(mrb_state*, struct RClass*);
size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*);
void mrb_gc_free_mt(mrb_state*, struct RClass*);
-#if defined(__cplusplus)
-} /* extern "C" { */
+#ifndef MRB_NO_METHOD_CACHE
+void mrb_mc_clear_by_class(mrb_state *mrb, struct RClass* c);
+#else
+#define mrb_mc_clear_by_class(mrb,c)
#endif
+/* return non zero to break the loop */
+typedef int (mrb_mt_foreach_func)(mrb_state*,mrb_sym,mrb_method_t,void*);
+MRB_API void mrb_mt_foreach(mrb_state*, struct RClass*, mrb_mt_foreach_func*, void*);
+
+MRB_END_DECL
+
#endif /* MRUBY_CLASS_H */
diff --git a/include/mruby/common.h b/include/mruby/common.h
new file mode 100644
index 000000000..90c97cf65
--- /dev/null
+++ b/include/mruby/common.h
@@ -0,0 +1,92 @@
+/**
+** @file common.h - mruby common platform definition"
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_COMMON_H
+#define MRUBY_COMMON_H
+
+#ifdef __APPLE__
+ #ifndef __TARGETCONDITIONALS__
+ #include "TargetConditionals.h"
+ #endif
+#endif
+
+#ifdef __cplusplus
+#ifdef MRB_USE_CXX_ABI
+#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
+/** End declarations in C mode */
+# define MRB_END_DECL
+#endif
+
+/**
+ * Shared compiler macros
+ */
+MRB_BEGIN_DECL
+
+/** Declare a function that never returns. */
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
+# define mrb_noreturn _Noreturn
+#elif defined __GNUC__ && !defined __STRICT_ANSI__
+# define mrb_noreturn __attribute__((noreturn))
+#elif defined _MSC_VER
+# define mrb_noreturn __declspec(noreturn)
+#else
+# define mrb_noreturn
+#endif
+
+/** Mark a function as deprecated. */
+#if defined __GNUC__ && !defined __STRICT_ANSI__
+# define mrb_deprecated __attribute__((deprecated))
+#elif defined _MSC_VER
+# define mrb_deprecated __declspec(deprecated)
+#else
+# define mrb_deprecated
+#endif
+
+/** Declare a function as always inlined. */
+#if defined _MSC_VER && _MSC_VER < 1900
+# ifndef __cplusplus
+# define inline __inline
+# endif
+#endif
+#define MRB_INLINE static inline
+
+/** Declare a public MRuby API function. */
+#ifndef MRB_API
+#if defined(MRB_BUILD_AS_DLL)
+#if defined(MRB_CORE) || defined(MRB_LIB)
+# define MRB_API __declspec(dllexport)
+#else
+# define MRB_API __declspec(dllimport)
+#endif
+#else
+# define MRB_API extern
+#endif
+#endif
+
+/** Declare mingw versions */
+#if defined(__MINGW32__) || defined(__MINGW64__)
+# include <_mingw.h>
+# if defined(__MINGW64_VERSION_MAJOR)
+# define MRB_MINGW64_VERSION (__MINGW64_VERSION_MAJOR * 1000 + __MINGW64_VERSION_MINOR)
+# elif defined(__MINGW32_MAJOR_VERSION)
+# define MRB_MINGW32_VERSION (__MINGW32_MAJOR_VERSION * 1000 + __MINGW32_MINOR_VERSION)
+# endif
+# if defined(__MINGW32__) && !defined(__MINGW64__)
+# define MRB_MINGW32_LEGACY
+# endif
+#endif
+
+MRB_END_DECL
+
+#endif /* MRUBY_COMMON_H */
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index 188df315d..6732625c1 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -1,5 +1,5 @@
-/*
-** mruby/compile.h - mruby parser
+/**
+** @file mruby/compile.h - mruby parser
**
** See Copyright Notice in mruby.h
*/
@@ -7,13 +7,14 @@
#ifndef MRUBY_COMPILE_H
#define MRUBY_COMPILE_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
-#include "mruby.h"
+/**
+ * MRuby Compiler
+ */
+MRB_BEGIN_DECL
-struct mrb_jmpbuf;
+#include <mruby.h>
struct mrb_parser_state;
/* load context */
@@ -21,7 +22,7 @@ typedef struct mrbc_context {
mrb_sym *syms;
int slen;
char *filename;
- short lineno;
+ uint16_t lineno;
int (*partial_hook)(struct mrb_parser_state*);
void *partial_data;
struct RClass *target_class;
@@ -29,14 +30,17 @@ typedef struct mrbc_context {
mrb_bool dump_result:1;
mrb_bool no_exec:1;
mrb_bool keep_lv:1;
-} mrbc_context;
+ mrb_bool no_optimize:1;
+ const struct RProc *upper;
-mrbc_context* mrbc_context_new(mrb_state *mrb);
-void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
-const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
-void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
+ size_t parser_nerr;
+} mrbc_context;
-mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int);
+MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb);
+MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
+MRB_API const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
+MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
+MRB_API void mrbc_cleanup_local_variables(mrb_state *mrb, mrbc_context *c);
/* AST node structure */
typedef struct mrb_ast_node {
@@ -54,15 +58,15 @@ enum mrb_lex_state_enum {
EXPR_CMDARG, /* newline significant, +/- is an operator. */
EXPR_MID, /* newline significant, +/- is an operator. */
EXPR_FNAME, /* ignore newline, no reserved words. */
- EXPR_DOT, /* right after `.' or `::', no reserved words. */
- EXPR_CLASS, /* immediate after `class', no here document. */
+ EXPR_DOT, /* right after '.' or '::', no reserved words. */
+ EXPR_CLASS, /* immediate after 'class', no here document. */
EXPR_VALUE, /* alike EXPR_BEG but label is disallowed. */
EXPR_MAX_STATE
};
/* saved error message */
struct mrb_parser_message {
- int lineno;
+ uint16_t lineno;
int column;
char* message;
};
@@ -93,6 +97,9 @@ enum mrb_string_type {
/* heredoc structure */
struct mrb_parser_heredoc_info {
mrb_bool allow_indent:1;
+ mrb_bool remove_indent:1;
+ size_t indent;
+ mrb_ast_node *indented;
mrb_bool line_head:1;
enum mrb_string_type type;
const char *term;
@@ -100,7 +107,8 @@ struct mrb_parser_heredoc_info {
mrb_ast_node *doc;
};
-#define MRB_PARSER_BUF_SIZE 1024
+#define MRB_PARSER_TOKBUF_MAX (UINT16_MAX-1)
+#define MRB_PARSER_TOKBUF_SIZE 256
/* parser structure */
struct mrb_parser_state {
@@ -108,12 +116,13 @@ struct mrb_parser_state {
struct mrb_pool *pool;
mrb_ast_node *cells;
const char *s, *send;
-#ifdef ENABLE_STDIO
+#ifndef MRB_NO_STDIO
+ /* If both f and s are non-null, it will be taken preferentially from s until s < send. */
FILE *f;
#endif
mrbc_context *cxt;
- char const *filename;
- int lineno;
+ mrb_sym filename_sym;
+ uint16_t lineno;
int column;
enum mrb_lex_state_enum lstate;
@@ -128,14 +137,15 @@ struct mrb_parser_state {
mrb_ast_node *locals;
mrb_ast_node *pb;
- char buf[MRB_PARSER_BUF_SIZE];
- int bidx;
+ char *tokbuf;
+ char buf[MRB_PARSER_TOKBUF_SIZE];
+ int tidx;
+ int tsiz;
- mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */
+ mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */
mrb_ast_node *heredocs_from_nextline;
mrb_ast_node *parsing_heredoc;
mrb_ast_node *lex_strterm_before_heredoc;
- mrb_bool heredoc_end_now:1; /* for mirb */
void *ylval;
@@ -143,46 +153,55 @@ struct mrb_parser_state {
size_t nwarn;
mrb_ast_node *tree;
+ mrb_bool no_optimize:1;
mrb_bool capture_errors:1;
+ const struct RProc *upper;
struct mrb_parser_message error_buffer[10];
struct mrb_parser_message warn_buffer[10];
mrb_sym* filename_table;
- size_t filename_table_length;
- int current_filename_index;
+ uint16_t filename_table_length;
+ uint16_t current_filename_index;
- struct mrb_jmpbuf* jmp;
+ mrb_ast_node *nvars;
};
-struct mrb_parser_state* mrb_parser_new(mrb_state*);
-void mrb_parser_free(struct mrb_parser_state*);
-void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*);
+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*);
-void mrb_parser_set_filename(struct mrb_parser_state*, char const*);
-char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
+MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*);
+MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
/* utility functions */
-#ifdef ENABLE_STDIO
-struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*);
+#ifndef MRB_NO_STDIO
+MRB_API struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*);
#endif
-struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*);
-struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,int,mrbc_context*);
-struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*);
-
-/* program load functions */
-#ifdef ENABLE_STDIO
-mrb_value mrb_load_file(mrb_state*,FILE*);
-#endif
-mrb_value mrb_load_string(mrb_state *mrb, const char *s);
-mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len);
-#ifdef ENABLE_STDIO
-mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt);
+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*,size_t,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
+* Please note! Currently due to interactions with the GC calling these functions will
+* leak one RProc object per function call.
+* To prevent this save the current memory arena before calling and restore the arena
+* right after, like so
+* int ai = mrb_gc_arena_save(mrb);
+* mrb_value status = mrb_load_string(mrb, buffer);
+* mrb_gc_arena_restore(mrb, ai);
+*/
+#ifndef MRB_NO_STDIO
+MRB_API mrb_value mrb_load_file(mrb_state*,FILE*);
+MRB_API mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt);
+MRB_API mrb_value mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrbc_context *c);
#endif
-mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt);
-mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *cxt);
+MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s);
+MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, size_t len);
+MRB_API mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt);
+MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *cxt);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+/** @} */
+MRB_END_DECL
#endif /* MRUBY_COMPILE_H */
diff --git a/include/mruby/data.h b/include/mruby/data.h
index 8b1b5edb7..7bdf1c34e 100644
--- a/include/mruby/data.h
+++ b/include/mruby/data.h
@@ -1,5 +1,5 @@
-/*
-** mruby/data.h - Data class
+/**
+** @file mruby/data.h - Data class
**
** See Copyright Notice in mruby.h
*/
@@ -7,12 +7,23 @@
#ifndef MRUBY_DATA_H
#define MRUBY_DATA_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+/**
+ * Custom C wrapped data.
+ *
+ * Defining Ruby wrappers around native objects.
+ */
+MRB_BEGIN_DECL
+
+/**
+ * Custom data type description.
+ */
typedef struct mrb_data_type {
+ /** data type name */
const char *struct_name;
+
+ /** data type release function pointer */
void (*dfree)(mrb_state *mrb, void*);
} mrb_data_type;
@@ -23,24 +34,25 @@ struct RData {
void *data;
};
-struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void *datap, const mrb_data_type *type);
+MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void *datap, const mrb_data_type *type);
#define Data_Wrap_Struct(mrb,klass,type,ptr)\
mrb_data_object_alloc(mrb,klass,ptr,type)
-#define Data_Make_Struct(mrb,klass,strct,type,sval,data) do { \
- sval = mrb_malloc(mrb, sizeof(strct)); \
- { static const strct zero = { 0 }; *sval = zero; };\
- data = Data_Wrap_Struct(mrb,klass,type,sval);\
+#define Data_Make_Struct(mrb,klass,strct,type,sval,data_obj) do { \
+ (data_obj) = Data_Wrap_Struct(mrb,klass,type,NULL);\
+ (sval) = (strct *)mrb_malloc(mrb, sizeof(strct)); \
+ { static const strct zero = { 0 }; *(sval) = zero; };\
+ (data_obj)->data = (sval);\
} while (0)
#define RDATA(obj) ((struct RData *)(mrb_ptr(obj)))
#define DATA_PTR(d) (RDATA(d)->data)
#define DATA_TYPE(d) (RDATA(d)->type)
-void mrb_data_check_type(mrb_state *mrb, mrb_value, const mrb_data_type*);
-void *mrb_data_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*);
+MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value, const mrb_data_type*);
+MRB_API void *mrb_data_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*);
#define DATA_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_get_ptr(mrb,obj,dtype)
-void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*);
+MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*);
#define DATA_CHECK_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_check_get_ptr(mrb,obj,dtype)
/* obsolete functions and macros */
@@ -51,8 +63,14 @@ void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*);
*(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \
} while (0)
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_INLINE void
+mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type)
+{
+ mrb_assert(mrb_data_p(v));
+ DATA_PTR(v) = ptr;
+ DATA_TYPE(v) = type;
+}
+
+MRB_END_DECL
#endif /* MRUBY_DATA_H */
diff --git a/include/mruby/debug.h b/include/mruby/debug.h
index a56321d42..7319ccb3f 100644
--- a/include/mruby/debug.h
+++ b/include/mruby/debug.h
@@ -1,5 +1,5 @@
-/*
-** mruby/debug.h - mruby debug info
+/**
+** @file mruby/debug.h - mruby debug info
**
** See Copyright Notice in mruby.h
*/
@@ -7,13 +7,17 @@
#ifndef MRUBY_DEBUG_H
#define MRUBY_DEBUG_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+
+/**
+ * MRuby Debugging.
+ */
+MRB_BEGIN_DECL
typedef enum mrb_debug_line_type {
mrb_debug_line_ary = 0,
- mrb_debug_line_flat_map = 1
+ mrb_debug_line_flat_map,
+ mrb_debug_line_packed_map
} mrb_debug_line_type;
typedef struct mrb_irep_debug_info_line {
@@ -23,14 +27,14 @@ typedef struct mrb_irep_debug_info_line {
typedef struct mrb_irep_debug_info_file {
uint32_t start_pos;
- const char *filename;
mrb_sym filename_sym;
uint32_t line_entry_count;
mrb_debug_line_type line_type;
union {
void *ptr;
- mrb_irep_debug_info_line *flat_map;
uint16_t *ary;
+ mrb_irep_debug_info_line *flat_map;
+ uint8_t *packed_map;
} lines;
} mrb_irep_debug_info_file;
@@ -44,22 +48,21 @@ typedef struct mrb_irep_debug_info {
* get line from irep's debug info and program counter
* @return returns NULL if not found
*/
-const char *mrb_debug_get_filename(mrb_irep *irep, uint32_t pc);
+MRB_API const char *mrb_debug_get_filename(mrb_state *mrb, const mrb_irep *irep, uint32_t pc);
/*
* get line from irep's debug info and program counter
* @return returns -1 if not found
*/
-int32_t mrb_debug_get_line(mrb_irep *irep, uint32_t pc);
+MRB_API int32_t mrb_debug_get_line(mrb_state *mrb, const mrb_irep *irep, uint32_t pc);
-mrb_irep_debug_info_file *mrb_debug_info_append_file(
- mrb_state *mrb, mrb_irep *irep,
+MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep);
+MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file(
+ mrb_state *mrb, mrb_irep_debug_info *info,
+ const char *filename, uint16_t *lines,
uint32_t start_pos, uint32_t end_pos);
-mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep);
-void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d);
+MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
#endif /* MRUBY_DEBUG_H */
diff --git a/include/mruby/dump.h b/include/mruby/dump.h
index fc79f1f4b..3c48866d9 100644
--- a/include/mruby/dump.h
+++ b/include/mruby/dump.h
@@ -1,5 +1,5 @@
-/*
-** mruby/dump.h - mruby binary dumper (mrbc binary format)
+/**
+** @file mruby/dump.h - mruby binary dumper (mrbc binary format)
**
** See Copyright Notice in mruby.h
*/
@@ -7,22 +7,31 @@
#ifndef MRUBY_DUMP_H
#define MRUBY_DUMP_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#include "mruby.h"
-#include "mruby/irep.h"
+#include <mruby.h>
+#include <mruby/irep.h>
+#include "common.h"
-int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size);
-#ifdef ENABLE_STDIO
-int mrb_dump_irep_binary(mrb_state*, mrb_irep*, int, FILE*);
-int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, int, FILE *f, const char *initname);
+/**
+ * Dumping compiled mruby script.
+ */
+MRB_BEGIN_DECL
+
+/* flags for mrb_dump_irep{,_binary,_cfunc,_cstruct} */
+#define MRB_DUMP_DEBUG_INFO 1
+#define MRB_DUMP_STATIC 2
+#define DUMP_DEBUG_INFO MRB_DUMP_DEBUG_INFO /* deprecated */
+
+int mrb_dump_irep(mrb_state *mrb, const mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size);
+#ifndef MRB_NO_STDIO
+int mrb_dump_irep_binary(mrb_state*, const mrb_irep*, uint8_t, FILE*);
+int mrb_dump_irep_cfunc(mrb_state *mrb, const mrb_irep*, uint8_t flags, FILE *f, const char *initname);
+int mrb_dump_irep_cstruct(mrb_state *mrb, const mrb_irep*, uint8_t flags, FILE *f, const char *initname);
mrb_irep *mrb_read_irep_file(mrb_state*, FILE*);
-mrb_value mrb_load_irep_file(mrb_state*,FILE*);
-mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*);
+MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*);
+MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*);
#endif
-mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
+MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
+MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t);
/* dump/load error code
*
@@ -33,35 +42,39 @@ mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
#define MRB_DUMP_GENERAL_FAILURE (-1)
#define MRB_DUMP_WRITE_FAULT (-2)
#define MRB_DUMP_READ_FAULT (-3)
-#define MRB_DUMP_CRC_ERROR (-4)
-#define MRB_DUMP_INVALID_FILE_HEADER (-5)
-#define MRB_DUMP_INVALID_IREP (-6)
-#define MRB_DUMP_INVALID_ARGUMENT (-7)
+#define MRB_DUMP_INVALID_FILE_HEADER (-4)
+#define MRB_DUMP_INVALID_IREP (-5)
+#define MRB_DUMP_INVALID_ARGUMENT (-6)
/* null symbol length */
#define MRB_DUMP_NULL_SYM_LEN 0xFFFF
/* Rite Binary File header */
-#define RITE_BINARY_IDENTIFIER "RITE"
-#define RITE_BINARY_FORMAT_VER "0002"
+#define RITE_BINARY_IDENT "RITE"
+/* Binary Format Version Major:Minor */
+/* Major: Incompatible to prior versions */
+/* Minor: Upper-compatible to prior versions */
+#define RITE_BINARY_MAJOR_VER "02"
+#define RITE_BINARY_MINOR_VER "00"
+#define RITE_BINARY_FORMAT_VER RITE_BINARY_MAJOR_VER RITE_BINARY_MINOR_VER
#define RITE_COMPILER_NAME "MATZ"
#define RITE_COMPILER_VERSION "0000"
-#define RITE_VM_VER "0000"
+#define RITE_VM_VER "0300"
#define RITE_BINARY_EOF "END\0"
-#define RITE_SECTION_IREP_IDENTIFIER "IREP"
-#define RITE_SECTION_LINENO_IDENTIFIER "LINE"
-#define RITE_SECTION_DEBUG_IDENTIFIER "DBG\0"
-#define RITE_SECTION_LV_IDENTIFIER "LVAR"
+#define RITE_SECTION_IREP_IDENT "IREP"
+#define RITE_SECTION_DEBUG_IDENT "DBG\0"
+#define RITE_SECTION_LV_IDENT "LVAR"
#define MRB_DUMP_DEFAULT_STR_LEN 128
+#define MRB_DUMP_ALIGNMENT sizeof(uint32_t)
/* binary header */
struct rite_binary_header {
- uint8_t binary_identify[4]; /* Binary Identifier */
- uint8_t binary_version[4]; /* Binary Format Version */
- uint8_t binary_crc[2]; /* Binary CRC */
+ uint8_t binary_ident[4]; /* Binary Identifier */
+ uint8_t major_version[2]; /* Binary Format Major Version */
+ uint8_t minor_version[2]; /* Binary Format Minor Version */
uint8_t binary_size[4]; /* Binary Size */
uint8_t compiler_name[4]; /* Compiler name */
uint8_t compiler_version[4];
@@ -69,7 +82,7 @@ struct rite_binary_header {
/* section header */
#define RITE_SECTION_HEADER \
- uint8_t section_identify[4]; \
+ uint8_t section_ident[4]; \
uint8_t section_size[4]
struct rite_section_header {
@@ -82,10 +95,6 @@ struct rite_section_irep_header {
uint8_t rite_version[4]; /* Rite Instruction Specification Version */
};
-struct rite_section_lineno_header {
- RITE_SECTION_HEADER;
-};
-
struct rite_section_debug_header {
RITE_SECTION_HEADER;
};
@@ -147,12 +156,6 @@ bin_to_uint8(const uint8_t *bin)
return (uint8_t)bin[0];
}
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
-
-/* crc.c */
-uint16_t
-calc_crc_16_ccitt(const uint8_t *src, size_t nbytes, uint16_t crc);
+MRB_END_DECL
#endif /* MRUBY_DUMP_H */
diff --git a/include/mruby/endian.h b/include/mruby/endian.h
new file mode 100644
index 000000000..477f3bc94
--- /dev/null
+++ b/include/mruby/endian.h
@@ -0,0 +1,44 @@
+/**
+** @file mruby/endian.h - detect endian-ness
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_ENDIAN_H
+#define MRUBY_ENDIAN_H
+
+#include <limits.h>
+
+MRB_BEGIN_DECL
+
+#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER__)
+# define BYTE_ORDER __BYTE_ORDER__
+#endif
+#if !defined(BIG_ENDIAN) && defined(__ORDER_BIG_ENDIAN__)
+# define BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif
+#if !defined(LITTLE_ENDIAN) && defined(__ORDER_LITTLE_ENDIAN__)
+# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#endif
+
+#ifdef BYTE_ORDER
+# if BYTE_ORDER == BIG_ENDIAN
+# define littleendian 0
+# elif BYTE_ORDER == LITTLE_ENDIAN
+# define littleendian 1
+# endif
+#endif
+#ifndef littleendian
+/* can't distinguish endian in compile time */
+static inline int
+check_little_endian(void)
+{
+ unsigned int n = 1;
+ return (*(unsigned char *)&n == 1);
+}
+# define littleendian check_little_endian()
+#endif
+
+MRB_END_DECL
+
+#endif /* MRUBY_ENDIAN_H */
diff --git a/include/mruby/error.h b/include/mruby/error.h
index ea12ef33e..80c21434f 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -1,5 +1,5 @@
-/*
-** error.h - Exception class
+/**
+** @file mruby/error.h - Exception class
**
** See Copyright Notice in mruby.h
*/
@@ -7,9 +7,12 @@
#ifndef MRUBY_ERROR_H
#define MRUBY_ERROR_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+
+/**
+ * MRuby error handling.
+ */
+MRB_BEGIN_DECL
struct RException {
MRB_OBJECT_HEADER;
@@ -20,21 +23,125 @@ struct RException {
#define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v))
#define MRB_EXC_MESG_STRING_FLAG 0x100
-void mrb_sys_fail(mrb_state *mrb, const char *mesg);
-mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
-#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
-mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv);
-void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
-void mrb_print_backtrace(mrb_state *mrb);
+MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg);
+MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
+#define mrb_exc_new_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
+#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_lit(mrb, c, lit)
+MRB_API mrb_value mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
mrb_value mrb_get_backtrace(mrb_state *mrb);
-mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...);
-/* declaration for fail method */
-mrb_value mrb_f_raise(mrb_state*, mrb_value);
+MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
+
+/* declaration for `fail` method */
+MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
+
+#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT32) || defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING)
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ const struct RProc *proc;
+ mrb_value val;
+};
+#define mrb_break_value_get(brk) ((brk)->val)
+#define mrb_break_value_set(brk, v) ((brk)->val = v)
+#else
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ const struct RProc *proc;
+ union mrb_value_union value;
+};
+#define RBREAK_VALUE_TT_MASK ((1 << 8) - 1)
+static inline mrb_value
+mrb_break_value_get(struct RBreak *brk)
+{
+ mrb_value val;
+ val.value = brk->value;
+ val.tt = (enum mrb_vtype)(brk->flags & RBREAK_VALUE_TT_MASK);
+ return val;
+}
+static inline void
+mrb_break_value_set(struct RBreak *brk, mrb_value val)
+{
+ brk->value = val.value;
+ brk->flags &= ~RBREAK_VALUE_TT_MASK;
+ brk->flags |= val.tt;
+}
+#endif /* MRB_64BIT || MRB_USE_FLOAT32 || MRB_NAN_BOXING || MRB_WORD_BOXING */
+#define mrb_break_proc_get(brk) ((brk)->proc)
+#define mrb_break_proc_set(brk, p) ((brk)->proc = p)
+
+#define RBREAK_TAG_FOREACH(f) \
+ f(RBREAK_TAG_BREAK, 0) \
+ f(RBREAK_TAG_BREAK_UPPER, 1) \
+ f(RBREAK_TAG_BREAK_INTARGET, 2) \
+ f(RBREAK_TAG_RETURN_BLOCK, 3) \
+ f(RBREAK_TAG_RETURN, 4) \
+ f(RBREAK_TAG_RETURN_TOPLEVEL, 5) \
+ f(RBREAK_TAG_JUMP, 6) \
+ f(RBREAK_TAG_STOP, 7)
+
+#define RBREAK_TAG_DEFINE(tag, i) tag = i,
+enum {
+ RBREAK_TAG_FOREACH(RBREAK_TAG_DEFINE)
+};
+#undef RBREAK_TAG_DEFINE
+
+#define RBREAK_TAG_BIT 3
+#define RBREAK_TAG_BIT_OFF 8
+#define RBREAK_TAG_MASK (~(~UINT32_C(0) << RBREAK_TAG_BIT))
+
+static inline uint32_t
+mrb_break_tag_get(struct RBreak *brk)
+{
+ return (brk->flags >> RBREAK_TAG_BIT_OFF) & RBREAK_TAG_MASK;
+}
+
+static inline void
+mrb_break_tag_set(struct RBreak *brk, uint32_t tag)
+{
+ brk->flags &= ~(RBREAK_TAG_MASK << RBREAK_TAG_BIT_OFF);
+ brk->flags |= (tag & RBREAK_TAG_MASK) << RBREAK_TAG_BIT_OFF;
+}
+
+/**
+ * Protect
+ *
+ */
+typedef mrb_value mrb_protect_error_func(mrb_state *mrb, void *userdata);
+MRB_API mrb_value mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, mrb_bool *error);
+
+/**
+ * Protect (takes mrb_value for body argument)
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state);
+
+/**
+ * Ensure
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data,
+ mrb_func_t ensure, mrb_value e_data);
+
+/**
+ * Rescue
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data,
+ mrb_func_t rescue, mrb_value r_data);
+
+/**
+ * Rescue exception
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data,
+ mrb_func_t rescue, mrb_value r_data,
+ mrb_int len, struct RClass **classes);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
#endif /* MRUBY_ERROR_H */
diff --git a/include/mruby/gc.h b/include/mruby/gc.h
index 02714be8e..9f9bba410 100644
--- a/include/mruby/gc.h
+++ b/include/mruby/gc.h
@@ -1,5 +1,5 @@
-/*
-** gc.h - garbage collector for mruby
+/**
+** @file mruby/gc.h - garbage collector for mruby
**
** See Copyright Notice in mruby.h
*/
@@ -7,16 +7,88 @@
#ifndef MRUBY_GC_H
#define MRUBY_GC_H
-#if defined(__cplusplus)
-extern "C" {
+#include "common.h"
+
+/**
+ * Uncommon memory management stuffs.
+ */
+MRB_BEGIN_DECL
+
+
+struct mrb_state;
+
+#define MRB_EACH_OBJ_OK 0
+#define MRB_EACH_OBJ_BREAK 1
+typedef int (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data);
+void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data);
+size_t mrb_objspace_page_slot_size(void);
+MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c);
+
+#ifndef MRB_GC_ARENA_SIZE
+#define MRB_GC_ARENA_SIZE 100
+#endif
+
+typedef enum {
+ MRB_GC_STATE_ROOT = 0,
+ MRB_GC_STATE_MARK,
+ MRB_GC_STATE_SWEEP
+} mrb_gc_state;
+
+/* Disable MSVC warning "C4200: nonstandard extension used: zero-sized array
+ * in struct/union" when in C++ mode */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4200)
#endif
-typedef void (mrb_each_object_callback)(mrb_state *mrb, struct RBasic *obj, void *data);
-void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data);
-void mrb_free_context(mrb_state *mrb, struct mrb_context *c);
+typedef struct mrb_heap_page {
+ struct RBasic *freelist;
+ struct mrb_heap_page *prev;
+ struct mrb_heap_page *next;
+ struct mrb_heap_page *free_next;
+ struct mrb_heap_page *free_prev;
+ mrb_bool old:1;
+ void *objects[];
+} mrb_heap_page;
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
-#if defined(__cplusplus)
-} /* extern "C" { */
+typedef struct mrb_gc {
+ mrb_heap_page *heaps; /* heaps for GC */
+ mrb_heap_page *sweeps;
+ mrb_heap_page *free_heaps;
+ size_t live; /* count of live objects */
+#ifdef MRB_GC_FIXED_ARENA
+ struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */
+#else
+ struct RBasic **arena; /* GC protection array */
+ int arena_capa;
#endif
+ int arena_idx;
+
+ mrb_gc_state state; /* state of gc */
+ int current_white_part; /* make white object by white_part */
+ struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */
+ struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */
+ size_t live_after_mark;
+ size_t threshold;
+ int interval_ratio;
+ int step_ratio;
+ mrb_bool iterating :1;
+ mrb_bool disabled :1;
+ mrb_bool full :1;
+ mrb_bool generational :1;
+ mrb_bool out_of_memory :1;
+ size_t majorgc_old_threshold;
+} mrb_gc;
+
+MRB_API mrb_bool
+mrb_object_dead_p(struct mrb_state *mrb, struct RBasic *object);
+
+#define MRB_GC_RED 7
+
+MRB_END_DECL
#endif /* MRUBY_GC_H */
diff --git a/include/mruby/hash.h b/include/mruby/hash.h
index 6a8b11373..1b37a12d4 100644
--- a/include/mruby/hash.h
+++ b/include/mruby/hash.h
@@ -1,5 +1,5 @@
-/*
-** mruby/hash.h - Hash class
+/**
+** @file mruby/hash.h - Hash class
**
** See Copyright Notice in mruby.h
*/
@@ -7,48 +7,234 @@
#ifndef MRUBY_HASH_H
#define MRUBY_HASH_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+/**
+ * Hash class
+ */
+MRB_BEGIN_DECL
+
+/* offset of `iv` must be 3 words */
struct RHash {
MRB_OBJECT_HEADER;
+#ifdef MRB_64BIT
+ uint32_t size;
+ struct iv_tbl *iv;
+ uint32_t ea_capa;
+ uint32_t ea_n_used;
+#else
struct iv_tbl *iv;
- struct kh_ht *ht;
+ uint32_t size;
+#endif
+ union {
+ struct hash_entry *ea;
+ struct hash_table *ht;
+ } hsh;
};
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
#define mrb_hash_value(p) mrb_obj_value((void*)(p))
-mrb_value mrb_hash_new_capa(mrb_state*, int);
-mrb_value mrb_hash_new(mrb_state *mrb);
+size_t mrb_hash_memsize(mrb_value obj);
+MRB_API mrb_value mrb_hash_new_capa(mrb_state *mrb, mrb_int capa);
+
+/*
+ * 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. 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);
-void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val);
-mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key);
-mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def);
-mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key);
-mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash);
-mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
-mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
-mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
+/*
+ * Gets a value from a key. If the key is not found, the default parameter is
+ * used.
+ *
+ * Equivalent to:
+ *
+ * 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);
-/* RHASH_TBL allocates st_table if not available. */
-#define RHASH(obj) ((struct RHash*)(mrb_ptr(obj)))
-#define RHASH_TBL(h) (RHASH(h)->ht)
-#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone"))
-#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h)
-struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash);
+/*
+ * 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. This value is not protected from GC. Use `mrb_gc_protect()` if necessary.
+ */
+MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key);
-#define MRB_HASH_PROC_DEFAULT 256
-#define MRB_RHASH_PROCDEFAULT_P(h) (RHASH(h)->flags & MRB_HASH_PROC_DEFAULT)
+/*
+ * 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);
+/*
+ * Check if the hash has the key.
+ *
+ * Equivalent to:
+ *
+ * hash.key?(key)
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @param key The key to check existence.
+ * @return True if the hash has the key
+ */
+MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key);
+
+/*
+ * 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_bool 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);
+
+/*
+ * Get hash size.
+ *
+ * Equivalent to:
+ *
+ * hash.size
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @return The hash size.
+ */
+MRB_API mrb_int mrb_hash_size(mrb_state *mrb, mrb_value hash);
+
+/*
+ * Copies the hash. This function does NOT copy the instance variables
+ * (except for the default value). Use mrb_obj_dup() to copy the instance
+ * variables as well.
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @return The copy of the hash
+ */
+MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash);
+
+/*
+ * Merges two hashes. The first hash will be modified by the
+ * second hash.
+ *
+ * @param mrb The mruby state reference.
+ * @param hash1 The target hash.
+ * @param hash2 Updating hash
+ */
+MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2);
+
+#define RHASH(hash) ((struct RHash*)(mrb_ptr(hash)))
+
+#define MRB_HASH_IB_BIT_BIT 5
+#define MRB_HASH_AR_EA_CAPA_BIT 5
+#define MRB_HASH_IB_BIT_SHIFT 0
+#define MRB_HASH_AR_EA_CAPA_SHIFT 0
+#define MRB_HASH_AR_EA_N_USED_SHIFT MRB_HASH_AR_EA_CAPA_BIT
+#define MRB_HASH_SIZE_FLAGS_SHIFT (MRB_HASH_AR_EA_CAPA_BIT * 2)
+#define MRB_HASH_IB_BIT_MASK ((1 << MRB_HASH_IB_BIT_BIT) - 1)
+#define MRB_HASH_AR_EA_CAPA_MASK ((1 << MRB_HASH_AR_EA_CAPA_BIT) - 1)
+#define MRB_HASH_AR_EA_N_USED_MASK (MRB_HASH_AR_EA_CAPA_MASK << MRB_HASH_AR_EA_N_USED_SHIFT)
+#define MRB_HASH_DEFAULT (1 << (MRB_HASH_SIZE_FLAGS_SHIFT + 0))
+#define MRB_HASH_PROC_DEFAULT (1 << (MRB_HASH_SIZE_FLAGS_SHIFT + 1))
+#define MRB_HASH_HT (1 << (MRB_HASH_SIZE_FLAGS_SHIFT + 2))
+#define MRB_RHASH_DEFAULT_P(hash) (RHASH(hash)->flags & MRB_HASH_DEFAULT)
+#define MRB_RHASH_PROCDEFAULT_P(hash) (RHASH(hash)->flags & MRB_HASH_PROC_DEFAULT)
/* GC functions */
void mrb_gc_mark_hash(mrb_state*, struct RHash*);
size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*);
void mrb_gc_free_hash(mrb_state*, struct RHash*);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+/* return non zero to break the loop */
+typedef int (mrb_hash_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data);
+MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p);
+
+MRB_END_DECL
#endif /* MRUBY_HASH_H */
diff --git a/include/mruby/irep.h b/include/mruby/irep.h
index 3d6b5efc7..2a0e261d1 100644
--- a/include/mruby/irep.h
+++ b/include/mruby/irep.h
@@ -1,5 +1,5 @@
-/*
-** mruby/irep.h - mrb_irep structure
+/**
+** @file mruby/irep.h - mrb_irep structure
**
** See Copyright Notice in mruby.h
*/
@@ -7,54 +7,141 @@
#ifndef MRUBY_IREP_H
#define MRUBY_IREP_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+#include <mruby/compile.h>
-#include "mruby/compile.h"
+/**
+ * Compiled mruby scripts.
+ */
+MRB_BEGIN_DECL
enum irep_pool_type {
- IREP_TT_STRING,
- IREP_TT_FIXNUM,
- IREP_TT_FLOAT,
+ IREP_TT_STR = 0, /* string (need free) */
+ IREP_TT_SSTR = 2, /* string (static) */
+ IREP_TT_INT32 = 1, /* 32bit integer */
+ IREP_TT_INT64 = 3, /* 64bit integer */
+ IREP_TT_BIGINT = 7, /* big integer (not yet supported) */
+ IREP_TT_FLOAT = 5, /* float (double/float) */
};
-struct mrb_locals {
- mrb_sym name;
- uint16_t r;
+#define IREP_TT_NFLAG 1 /* number (non string) flag */
+#define IREP_TT_SFLAG 2 /* static string flag */
+
+typedef struct mrb_pool_value {
+ uint32_t tt; /* packed type and length (for string) */
+ union {
+ const char *str;
+ int32_t i32;
+ int64_t i64;
+#ifndef MRB_NO_FLOAT
+ mrb_float f;
+#endif
+ } u;
+} mrb_pool_value;
+
+enum mrb_catch_type {
+ MRB_CATCH_RESCUE = 0,
+ MRB_CATCH_ENSURE = 1,
+};
+
+struct mrb_irep_catch_handler {
+ uint8_t type; /* enum mrb_catch_type */
+ uint8_t begin[4]; /* The starting address to match the handler. Includes this. */
+ uint8_t end[4]; /* The endpoint address that matches the handler. Not Includes this. */
+ uint8_t target[4]; /* The address to jump to if a match is made. */
};
/* Program data array struct */
typedef struct mrb_irep {
uint16_t nlocals; /* Number of local variables */
uint16_t nregs; /* Number of register variables */
+ uint16_t clen; /* Number of catch handlers */
uint8_t flags;
- mrb_code *iseq;
- mrb_value *pool;
- mrb_sym *syms;
- struct mrb_irep **reps;
+ const mrb_code *iseq;
+ /*
+ * A catch handler table is placed after the iseq entity.
+ * The reason it doesn't add fields to the structure is to keep the mrb_irep structure from bloating.
+ * The catch handler table can be obtained with `mrb_irep_catch_handler_table(irep)`.
+ */
+ const mrb_pool_value *pool;
+ const mrb_sym *syms;
+ const struct mrb_irep * const *reps;
- struct mrb_locals *lv;
+ const mrb_sym *lv;
/* debug info */
- const char *filename;
- uint16_t *lines;
struct mrb_irep_debug_info* debug_info;
- size_t ilen, plen, slen, rlen, refcnt;
+ uint32_t ilen;
+ uint16_t plen, slen;
+ uint16_t rlen;
+ uint16_t refcnt;
} mrb_irep;
#define MRB_ISEQ_NO_FREE 1
+#define MRB_IREP_NO_FREE 2
+#define MRB_IREP_STATIC (MRB_ISEQ_NO_FREE | MRB_IREP_NO_FREE)
+
+MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb);
+
+/** load mruby bytecode functions
+* Please note! Currently due to interactions with the GC calling these functions will
+* leak one RProc object per function call.
+* To prevent this save the current memory arena before calling and restore the arena
+* right after, like so
+* int ai = mrb_gc_arena_save(mrb);
+* mrb_value status = mrb_load_irep(mrb, buffer);
+* mrb_gc_arena_restore(mrb, ai);
+*/
+
+/* @param [const uint8_t*] irep code, expected as a literal */
+MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*);
+
+/*
+ * @param [const void*] irep code
+ * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted.
+ */
+MRB_API mrb_value mrb_load_irep_buf(mrb_state*, const void*, size_t);
+
+/* @param [const uint8_t*] irep code, expected as a literal */
+MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*);
+
+/*
+ * @param [const void*] irep code
+ * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted.
+ */
+MRB_API mrb_value mrb_load_irep_buf_cxt(mrb_state*, const void*, size_t, mrbc_context*);
-mrb_irep *mrb_add_irep(mrb_state *mrb);
-mrb_value mrb_load_irep(mrb_state*, const uint8_t*);
-mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*);
void mrb_irep_free(mrb_state*, struct mrb_irep*);
void mrb_irep_incref(mrb_state*, struct mrb_irep*);
void mrb_irep_decref(mrb_state*, struct mrb_irep*);
+void mrb_irep_cutref(mrb_state*, struct mrb_irep*);
+void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+struct mrb_insn_data {
+ uint8_t insn;
+ uint16_t a;
+ uint16_t b;
+ uint8_t c;
+ const mrb_code *addr;
+};
+
+struct mrb_insn_data mrb_decode_insn(const mrb_code *pc);
+
+static inline const struct mrb_irep_catch_handler *
+mrb_irep_catch_handler_table(const struct mrb_irep *irep)
+{
+ if (irep->clen > 0) {
+ return (const struct mrb_irep_catch_handler*)(irep->iseq + irep->ilen);
+ }
+ else {
+ return (const struct mrb_irep_catch_handler*)NULL;
+ }
+}
+
+#define mrb_irep_catch_handler_pack(n, v) uint32_to_bin(n, v)
+#define mrb_irep_catch_handler_unpack(v) bin_to_uint32(v)
+
+MRB_END_DECL
#endif /* MRUBY_IREP_H */
diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h
new file mode 100644
index 000000000..d6b6116a7
--- /dev/null
+++ b/include/mruby/istruct.h
@@ -0,0 +1,50 @@
+/**
+** @file 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;
+ union {
+ intptr_t inline_alignment[3];
+ 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 */
diff --git a/include/mruby/khash.h b/include/mruby/khash.h
index d2501dd52..1fb6eecbb 100644
--- a/include/mruby/khash.h
+++ b/include/mruby/khash.h
@@ -1,19 +1,22 @@
-/*
-** mruby/khash.c - Hash for mruby
+/**
+** @file mruby/khash.h - Hash for mruby
**
** See Copyright Notice in mruby.h
*/
-#ifndef KHASH_H
-#define KHASH_H
+#ifndef MRUBY_KHASH_H
+#define MRUBY_KHASH_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#include "mruby.h"
#include <string.h>
+#include <mruby.h>
+#include "common.h"
+
+/**
+ * khash definitions used in mruby's hash table.
+ */
+MRB_BEGIN_DECL
+
typedef uint32_t khint_t;
typedef khint_t khiter_t;
@@ -58,7 +61,6 @@ static const uint8_t __m_either[] = {0x03, 0x0c, 0x30, 0xc0};
typedef struct kh_##name { \
khint_t n_buckets; \
khint_t size; \
- khint_t n_occupied; \
uint8_t *ed_flags; \
khkey_t *keys; \
khval_t *vals; \
@@ -89,19 +91,28 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
khval_t: value data type
kh_is_map: (0: hash set / 1: hash map)
__hash_func: hash function
- __hash_equal: hash comparation function
+ __hash_equal: hash comparison function
*/
#define KHASH_DEFINE(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
- void kh_alloc_##name(mrb_state *mrb, kh_##name##_t *h) \
+ mrb_noreturn void mrb_raise_nomemory(mrb_state *mrb); \
+ int kh_alloc_simple_##name(mrb_state *mrb, kh_##name##_t *h) \
{ \
khint_t sz = h->n_buckets; \
size_t len = sizeof(khkey_t) + (kh_is_map ? sizeof(khval_t) : 0); \
- uint8_t *p = (uint8_t*)mrb_malloc(mrb, sizeof(uint8_t)*sz/4+len*sz); \
- h->size = h->n_occupied = 0; \
+ uint8_t *p = (uint8_t*)mrb_malloc_simple(mrb, sizeof(uint8_t)*sz/4+len*sz); \
+ if (!p) { return 1; } \
+ h->size = 0; \
h->keys = (khkey_t *)p; \
h->vals = kh_is_map ? (khval_t *)(p+sizeof(khkey_t)*sz) : NULL; \
h->ed_flags = p+len*sz; \
kh_fill_flags(h->ed_flags, 0xaa, sz/4); \
+ return 0; \
+ } \
+ void kh_alloc_##name(mrb_state *mrb, kh_##name##_t *h) \
+ { \
+ if (kh_alloc_simple_##name(mrb, h)) { \
+ mrb_raise_nomemory(mrb); \
+ } \
} \
kh_##name##_t *kh_init_##name##_size(mrb_state *mrb, khint_t size) { \
kh_##name##_t *h = (kh_##name##_t*)mrb_calloc(mrb, 1, sizeof(kh_##name##_t)); \
@@ -109,7 +120,10 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
size = KHASH_MIN_SIZE; \
khash_power2(size); \
h->n_buckets = size; \
- kh_alloc_##name(mrb, h); \
+ if (kh_alloc_simple_##name(mrb, h)) { \
+ mrb_free(mrb, h); \
+ mrb_raise_nomemory(mrb); \
+ } \
return h; \
} \
kh_##name##_t *kh_init_##name(mrb_state *mrb) { \
@@ -127,7 +141,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
(void)mrb; \
if (h && h->ed_flags) { \
kh_fill_flags(h->ed_flags, 0xaa, h->n_buckets/4); \
- h->size = h->n_occupied = 0; \
+ h->size = 0; \
} \
} \
khint_t kh_get_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key) \
@@ -148,27 +162,30 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
new_n_buckets = KHASH_MIN_SIZE; \
khash_power2(new_n_buckets); \
{ \
+ kh_##name##_t hh; \
uint8_t *old_ed_flags = h->ed_flags; \
khkey_t *old_keys = h->keys; \
khval_t *old_vals = h->vals; \
khint_t old_n_buckets = h->n_buckets; \
khint_t i; \
- h->n_buckets = new_n_buckets; \
- kh_alloc_##name(mrb, h); \
+ hh.n_buckets = new_n_buckets; \
+ kh_alloc_##name(mrb, &hh); \
/* relocate */ \
for (i=0 ; i<old_n_buckets ; i++) { \
if (!__ac_iseither(old_ed_flags, i)) { \
- khint_t k = kh_put_##name(mrb, h, old_keys[i], NULL); \
- if (kh_is_map) kh_value(h,k) = old_vals[i]; \
+ khint_t k = kh_put_##name(mrb, &hh, old_keys[i], NULL); \
+ if (kh_is_map) kh_value(&hh,k) = old_vals[i]; \
} \
} \
+ /* copy hh to h */ \
+ *h = hh; \
mrb_free(mrb, old_keys); \
} \
} \
khint_t kh_put_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t k, del_k, step = 0; \
- if (h->n_occupied >= khash_upper_bound(h)) { \
+ if (h->size >= khash_upper_bound(h)) { \
kh_resize_##name(mrb, h, h->n_buckets*2); \
} \
k = __hash_func(mrb,key) & khash_mask(h); \
@@ -198,7 +215,6 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
h->keys[k] = key; \
h->ed_flags[k/4] &= ~__m_empty[k%4]; \
h->size++; \
- h->n_occupied++; \
if (ret) *ret = 1; \
return k; \
} \
@@ -263,8 +279,6 @@ static inline khint_t __ac_X31_hash_string(const char *s)
typedef const char *kh_cstr_t;
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
-#endif /* KHASH_H */
+#endif /* MRUBY_KHASH_H */
diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h
index fe4f3b264..4b14588ac 100644
--- a/include/mruby/numeric.h
+++ b/include/mruby/numeric.h
@@ -1,5 +1,5 @@
-/*
-** mruby/numeric.h - Numeric, Integer, Float, Fixnum class
+/**
+** @file mruby/numeric.h - Numeric, Integer, Float class
**
** See Copyright Notice in mruby.h
*/
@@ -7,61 +7,172 @@
#ifndef MRUBY_NUMERIC_H
#define MRUBY_NUMERIC_H
-#if defined(__cplusplus)
-extern "C" {
+#include "common.h"
+
+/**
+ * Numeric class and it's sub-classes.
+ *
+ * Integer and Float
+ */
+MRB_BEGIN_DECL
+
+#define TYPED_POSFIXABLE(f,t) ((f) <= (t)MRB_FIXNUM_MAX)
+#define TYPED_NEGFIXABLE(f,t) ((f) >= (t)MRB_FIXNUM_MIN)
+#define TYPED_FIXABLE(f,t) (TYPED_POSFIXABLE(f,t) && TYPED_NEGFIXABLE(f,t))
+#define POSFIXABLE(f) TYPED_POSFIXABLE(f,mrb_int)
+#define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int)
+#define FIXABLE(f) TYPED_FIXABLE(f,mrb_int)
+#ifndef MRB_NO_FLOAT
+#ifdef MRB_INT64
+#define FIXABLE_FLOAT(f) ((f)>=-9223372036854775808.0 && (f)<9223372036854775808.0)
+#else
+#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,mrb_float)
+#endif
#endif
-#define POSFIXABLE(f) ((f) <= MRB_INT_MAX)
-#define NEGFIXABLE(f) ((f) >= MRB_INT_MIN)
-#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
+MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y);
+MRB_API mrb_value mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y);
+MRB_API mrb_value mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y);
-mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val);
+MRB_API mrb_value mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base);
+MRB_API char *mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base);
-mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base);
+/* internal function(s) */
+mrb_int mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y);
-mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y);
-mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y);
-mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y);
-mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y);
-mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x);
+/* obsolete function(s); will be removed */
+#define mrb_fixnum_to_str(mrb, x, base) mrb_integer_to_str(mrb, x, base)
-#define MRB_UINT_MAKE2(n) uint ## n ## _t
-#define MRB_UINT_MAKE(n) MRB_UINT_MAKE2(n)
-#define mrb_uint MRB_UINT_MAKE(MRB_INT_BIT)
+#ifndef __has_builtin
+ #define __has_builtin(x) 0
+#endif
-#ifdef MRB_WORD_BOXING
-# define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1 - MRB_FIXNUM_SHIFT))
-#else
-# define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1))
+#if (defined(__GNUC__) && __GNUC__ >= 5) || \
+ (__has_builtin(__builtin_add_overflow) && \
+ __has_builtin(__builtin_sub_overflow) && \
+ __has_builtin(__builtin_mul_overflow))
+# define MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
+#endif
+
+/*
+// Clang 3.8 and 3.9 have problem compiling mruby in 32-bit mode, when MRB_INT64 is set
+// because of missing __mulodi4 and similar functions in its runtime. We need to use custom
+// implementation for them.
+*/
+#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
+#if defined(__clang__) && (__clang_major__ == 3) && (__clang_minor__ >= 8) && \
+ defined(MRB_32BIT) && defined(MRB_INT64)
+#undef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#endif
+#endif
+
+#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
static inline mrb_bool
mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum)
{
- mrb_uint x = (mrb_uint)augend;
- mrb_uint y = (mrb_uint)addend;
+ return __builtin_add_overflow(augend, addend, sum);
+}
+
+static inline mrb_bool
+mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
+{
+ return __builtin_sub_overflow(minuend, subtrahend, difference);
+}
+
+static inline mrb_bool
+mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product)
+{
+ return __builtin_mul_overflow(multiplier, multiplicand, product);
+}
+
+#else
+
+#define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1))
+
+static inline mrb_bool
+mrb_int_add_overflow(mrb_int a, mrb_int b, mrb_int *c)
+{
+ mrb_uint x = (mrb_uint)a;
+ mrb_uint y = (mrb_uint)b;
mrb_uint z = (mrb_uint)(x + y);
- *sum = (mrb_int)z;
+ *c = (mrb_int)z;
return !!(((x ^ z) & (y ^ z)) & MRB_INT_OVERFLOW_MASK);
}
static inline mrb_bool
-mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
+mrb_int_sub_overflow(mrb_int a, mrb_int b, mrb_int *c)
{
- mrb_uint x = (mrb_uint)minuend;
- mrb_uint y = (mrb_uint)subtrahend;
+ mrb_uint x = (mrb_uint)a;
+ mrb_uint y = (mrb_uint)b;
mrb_uint z = (mrb_uint)(x - y);
- *difference = (mrb_int)z;
+ *c = (mrb_int)z;
return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK);
}
+static inline mrb_bool
+mrb_int_mul_overflow(mrb_int a, mrb_int b, mrb_int *c)
+{
+#ifdef MRB_INT32
+ int64_t n = (int64_t)a * b;
+ *c = (mrb_int)n;
+ return n > MRB_INT_MAX || n < MRB_INT_MIN;
+#else /* MRB_INT64 */
+ if (a > 0 && b > 0 && a > MRB_INT_MAX / b) return TRUE;
+ if (a < 0 && b > 0 && a < MRB_INT_MIN / b) return TRUE;
+ if (a > 0 && b < 0 && b < MRB_INT_MIN / a) return TRUE;
+ if (a < 0 && b < 0 && (a <= MRB_INT_MIN || b <= MRB_INT_MIN || -a > MRB_INT_MAX / -b))
+ return TRUE;
+ *c = a * b;
+ return FALSE;
+#endif
+}
+
#undef MRB_INT_OVERFLOW_MASK
-#undef mrb_uint
-#undef MRB_UINT_MAKE
-#undef MRB_UINT_MAKE2
-#if defined(__cplusplus)
-} /* extern "C" { */
#endif
+#ifndef MRB_NO_FLOAT
+
+# define MRB_FLT_RADIX FLT_RADIX
+
+# ifdef MRB_USE_FLOAT32
+# define MRB_FLT_MANT_DIG FLT_MANT_DIG
+# define MRB_FLT_EPSILON FLT_EPSILON
+# define MRB_FLT_DIG FLT_DIG
+# define MRB_FLT_MIN_EXP FLT_MIN_EXP
+# define MRB_FLT_MIN FLT_MIN
+# define MRB_FLT_MIN_10_EXP FLT_MIN_10_EXP
+# define MRB_FLT_MAX_EXP FLT_MAX_EXP
+# define MRB_FLT_MAX FLT_MAX
+# define MRB_FLT_MAX_10_EXP FLT_MAX_10_EXP
+
+# else /* not MRB_USE_FLOAT32 */
+# define MRB_FLT_MANT_DIG DBL_MANT_DIG
+# define MRB_FLT_EPSILON DBL_EPSILON
+# define MRB_FLT_DIG DBL_DIG
+# define MRB_FLT_MIN_EXP DBL_MIN_EXP
+# define MRB_FLT_MIN DBL_MIN
+# define MRB_FLT_MIN_10_EXP DBL_MIN_10_EXP
+# define MRB_FLT_MAX_EXP DBL_MAX_EXP
+# define MRB_FLT_MAX DBL_MAX
+# define MRB_FLT_MAX_10_EXP DBL_MAX_10_EXP
+# endif /* MRB_USE_FLOAT32 */
+
+MRB_API mrb_value mrb_float_to_integer(mrb_state *mrb, mrb_value val);
+MRB_API mrb_float mrb_as_float(mrb_state *mrb, mrb_value x);
+
+/* internal functions */
+mrb_float mrb_div_float(mrb_float x, mrb_float y);
+mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt);
+int mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign);
+
+/* obsolete functions; will be removed */
+#define mrb_flo_to_fixnum(mrb, val) mrb_float_to_integer(mrb, val)
+#define mrb_to_flo(mrb, x) mrb_as_float(mrb, x)
+
+#endif /* MRB_NO_FLOAT */
+
+MRB_END_DECL
+
#endif /* MRUBY_NUMERIC_H */
diff --git a/include/mruby/object.h b/include/mruby/object.h
index 56917a021..f75e99f1b 100644
--- a/include/mruby/object.h
+++ b/include/mruby/object.h
@@ -1,5 +1,5 @@
-/*
-** mruby/object.h - mruby object definition
+/**
+** @file mruby/object.h - mruby object definition
**
** See Copyright Notice in mruby.h
*/
@@ -8,46 +8,31 @@
#define MRUBY_OBJECT_H
#define MRB_OBJECT_HEADER \
- enum mrb_vtype tt:8;\
- uint32_t color:3;\
- uint32_t flags:21;\
- struct RClass *c;\
- struct RBasic *gcnext
-
-/* white: 011, black: 100, gray: 000 */
-#define MRB_GC_GRAY 0
-#define MRB_GC_WHITE_A 1
-#define MRB_GC_WHITE_B (1 << 1)
-#define MRB_GC_BLACK (1 << 2)
-#define MRB_GC_WHITES (MRB_GC_WHITE_A | MRB_GC_WHITE_B)
-#define MRB_GC_COLOR_MASK 7
-
-#define paint_gray(o) ((o)->color = MRB_GC_GRAY)
-#define paint_black(o) ((o)->color = MRB_GC_BLACK)
-#define paint_white(o) ((o)->color = MRB_GC_WHITES)
-#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part)
-#define is_gray(o) ((o)->color == MRB_GC_GRAY)
-#define is_white(o) ((o)->color & MRB_GC_WHITES)
-#define is_black(o) ((o)->color & MRB_GC_BLACK)
-#define is_dead(s, o) (((o)->color & other_white_part(s) & MRB_GC_WHITES) || (o)->tt == MRB_TT_FREE)
-#define flip_white_part(s) ((s)->current_white_part = other_white_part(s))
-#define other_white_part(s) ((s)->current_white_part ^ MRB_GC_WHITES)
+ struct RClass *c; \
+ struct RBasic *gcnext; \
+ enum mrb_vtype tt:8; \
+ uint32_t color:3; \
+ uint32_t flags:21
+
+#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & (flag))
struct RBasic {
MRB_OBJECT_HEADER;
};
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v)))
-/* obsolete macro mrb_basic; will be removed soon */
-#define mrb_basic(v) mrb_basic_ptr(v)
+
+#define MRB_FL_OBJ_IS_FROZEN (1 << 20)
+#define MRB_FROZEN_P(o) ((o)->flags & MRB_FL_OBJ_IS_FROZEN)
+#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FL_OBJ_IS_FROZEN)
+#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FL_OBJ_IS_FROZEN)
+#define mrb_frozen_p(o) MRB_FROZEN_P(o)
struct RObject {
MRB_OBJECT_HEADER;
struct iv_tbl *iv;
};
#define mrb_obj_ptr(v) ((struct RObject*)(mrb_ptr(v)))
-/* obsolete macro mrb_object; will be removed soon */
-#define mrb_object(o) mrb_obj_ptr(o)
-#define mrb_immediate_p(x) (mrb_type(x) < MRB_TT_HAS_BASIC)
+
#define mrb_special_const_p(x) mrb_immediate_p(x)
struct RFiber {
diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h
index c8a47c273..249598161 100644
--- a/include/mruby/opcode.h
+++ b/include/mruby/opcode.h
@@ -1,150 +1,16 @@
-/*
-** opcode.h - RiteVM operation codes
+/**
+** @file mruby/opcode.h - RiteVM operation codes
**
** See Copyright Notice in mruby.h
*/
-#ifndef OPCODE_H
-#define OPCODE_H
+#ifndef MRUBY_OPCODE_H
+#define MRUBY_OPCODE_H
-#define MAXARG_Bx (0xffff)
-#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */
-
-/* instructions: packed 32 bit */
-/* ------------------------------- */
-/* A:B:C:OP = 9: 9: 7: 7 */
-/* A:Bx:OP = 9:16: 7 */
-/* Ax:OP = 25: 7 */
-/* A:Bz:Cz:OP = 9:14: 2: 7 */
-
-#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f))
-#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff))
-#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff))
-#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f))
-#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff))
-#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx))
-#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff))
-#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1))))
-#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1))))
-#define GETARG_b(i) GETARG_UNPACK_b(i,14,2)
-#define GETARG_c(i) GETARG_UNPACK_c(i,14,2)
-
-#define MKOPCODE(op) ((op) & 0x7f)
-#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23)
-#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14)
-#define MKARG_C(c) (((c) & 0x7f) << 7)
-#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7)
-#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx)
-#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7)
-#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7))
-#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2)
-
-#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a))
-#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b))
-#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c))
-#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx))
-#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx))
-#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx))
-#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx))
-#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax))
-#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c))
-
-enum {
- /*-----------------------------------------------------------------------
- operation code operand description
- ------------------------------------------------------------------------*/
- OP_NOP=0,/* */
- OP_MOVE,/* A B R(A) := R(B) */
- OP_LOADL,/* A Bx R(A) := Pool(Bx) */
- OP_LOADI,/* A sBx R(A) := sBx */
- OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */
- OP_LOADNIL,/* A R(A) := nil */
- OP_LOADSELF,/* A R(A) := self */
- OP_LOADT,/* A R(A) := true */
- OP_LOADF,/* A R(A) := false */
-
- OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */
- OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */
- OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */
- OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */
- OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */
- OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */
- OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */
- OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */
- OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */
- OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */
- OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */
- OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */
- OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */
- OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */
-
- OP_JMP,/* sBx pc+=sBx */
- OP_JMPIF,/* A sBx if R(A) pc+=sBx */
- OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */
- OP_ONERR,/* sBx rescue_push(pc+sBx) */
- OP_RESCUE,/* A clear(exc); R(A) := exception (ignore when A=0) */
- OP_POPERR,/* A A.times{rescue_pop()} */
- OP_RAISE,/* A raise(R(A)) */
- OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */
- OP_EPOP,/* A A.times{ensure_pop().call} */
-
- OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
- OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
- OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */
- OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */
- OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
- OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */
- OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
- OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
- OP_KDICT,/* A C R(A) := kdict */
-
- OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */
- OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */
- OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */
-
- OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */
- OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */
- OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */
- OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */
- OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */
- OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */
- OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */
- OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */
- OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */
- OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */
- OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */
-
- OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
- OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */
- OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */
- OP_AREF,/* A B C R(A) := R(B)[C] */
- OP_ASET,/* A B C R(B)[C] := R(A) */
- OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A) */
-
- OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */
- OP_STRCAT,/* A B str_cat(R(A),R(B)) */
-
- OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
- OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */
- OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */
-
- OP_OCLASS,/* A R(A) := ::Object */
- OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
- OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */
- OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
- OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */
- OP_SCLASS,/* A B R(A) := R(B).singleton_class */
- OP_TCLASS,/* A R(A) := target_class */
-
- OP_DEBUG,/* A B C print R(A),R(B),R(C) */
- OP_STOP,/* stop VM */
- OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */
-
- OP_RSVD1,/* reserved instruction #1 */
- OP_RSVD2,/* reserved instruction #2 */
- OP_RSVD3,/* reserved instruction #3 */
- OP_RSVD4,/* reserved instruction #4 */
- OP_RSVD5,/* reserved instruction #5 */
+enum mrb_insn {
+#define OPCODE(x,_) OP_ ## x,
+#include "mruby/ops.h"
+#undef OPCODE
};
#define OP_L_STRICT 1
@@ -157,4 +23,51 @@ enum {
#define OP_R_BREAK 1
#define OP_R_RETURN 2
-#endif /* OPCODE_H */
+#define PEEK_B(pc) (*(pc))
+#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1])
+#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2])
+
+#define READ_B() PEEK_B(pc++)
+#define READ_S() (pc+=2, PEEK_S(pc-2))
+#define READ_W() (pc+=3, PEEK_W(pc-3))
+
+#define FETCH_Z() /* nothing */
+#define FETCH_B() do {a=READ_B();} while (0)
+#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0)
+#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0)
+#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0)
+#define FETCH_BSS() do {a=READ_B(); b=READ_S(); c=READ_S();} while (0)
+#define FETCH_S() do {a=READ_S();} while (0)
+#define FETCH_W() do {a=READ_W();} while (0)
+
+/* with OP_EXT1 (1st 16bit) */
+#define FETCH_Z_1() FETCH_Z()
+#define FETCH_B_1() FETCH_S()
+#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0)
+#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0)
+#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_BSS_1() do {a=READ_S(); b=READ_S();c=READ_S();} while (0)
+#define FETCH_S_1() FETCH_S()
+#define FETCH_W_1() FETCH_W()
+
+/* with OP_EXT2 (2nd 16bit) */
+#define FETCH_Z_2() FETCH_Z()
+#define FETCH_B_2() FETCH_B()
+#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0)
+#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0)
+#define FETCH_BS_2() FETCH_BS()
+#define FETCH_BSS_2() FETCH_BSS()
+#define FETCH_S_2() FETCH_S()
+#define FETCH_W_2() FETCH_W()
+
+/* with OP_EXT3 (1st & 2nd 16bit) */
+#define FETCH_Z_3() FETCH_Z()
+#define FETCH_B_3() FETCH_B()
+#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0)
+#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_BSS_3() FETCH_BSS_1()
+#define FETCH_S_3() FETCH_S()
+#define FETCH_W_3() FETCH_W()
+
+#endif /* MRUBY_OPCODE_H */
diff --git a/include/mruby/ops.h b/include/mruby/ops.h
new file mode 100644
index 000000000..af7051833
--- /dev/null
+++ b/include/mruby/ops.h
@@ -0,0 +1,118 @@
+/* operand types:
+ + Z: no operand
+ + B: 8bit
+ + BB: 8+8bit
+ + BBB: 8+8+8bit
+ + BS: 8+16bit
+ + BSS: 8+16+16bit
+ + S: 16bit
+ + W: 24bit
+*/
+
+/*-----------------------------------------------------------------------
+operation code operands semantics
+------------------------------------------------------------------------*/
+OPCODE(NOP, Z) /* no operation */
+OPCODE(MOVE, BB) /* R(a) = R(b) */
+OPCODE(LOADL, BB) /* R(a) = Pool(b) */
+OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */
+OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */
+OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */
+OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */
+OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */
+OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */
+OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */
+OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */
+OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */
+OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */
+OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */
+OPCODE(LOADI16, BS) /* R(a) = mrb_int(b) */
+OPCODE(LOADI32, BSS) /* R(a) = mrb_int((b<<16)+c) */
+OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */
+OPCODE(LOADNIL, B) /* R(a) = nil */
+OPCODE(LOADSELF, B) /* R(a) = self */
+OPCODE(LOADT, B) /* R(a) = true */
+OPCODE(LOADF, B) /* R(a) = false */
+OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */
+OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */
+OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */
+OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */
+OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */
+OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */
+OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */
+OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */
+OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */
+OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */
+OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */
+OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */
+OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */
+OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */
+OPCODE(GETIDX, B) /* R(a) = R(a)[R(a+1)] */
+OPCODE(SETIDX, B) /* R(a)[R(a+1)] = R(a+2) */
+OPCODE(JMP, S) /* pc+=a */
+OPCODE(JMPIF, BS) /* if R(a) pc+=b */
+OPCODE(JMPNOT, BS) /* if !R(a) pc+=b */
+OPCODE(JMPNIL, BS) /* if R(a)==nil pc+=b */
+OPCODE(JMPUW, S) /* unwind_and_jump_to(a) */
+OPCODE(EXCEPT, B) /* R(a) = exc */
+OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */
+OPCODE(RAISEIF, B) /* raise(R(a)) if R(a) */
+OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..) (c=n|k<<4) */
+OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..,&R(a+n+2k+1)) */
+OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */
+OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */
+OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */
+OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */
+OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) */
+OPCODE(KEYEND, Z) /* raise unless kdict.empty? */
+OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) */
+OPCODE(RETURN, B) /* return R(a) (normal) */
+OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */
+OPCODE(BREAK, B) /* break R(a) */
+OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */
+OPCODE(ADD, B) /* R(a) = R(a)+R(a+1) */
+OPCODE(ADDI, BB) /* R(a) = R(a)+mrb_int(b) */
+OPCODE(SUB, B) /* R(a) = R(a)-R(a+1) */
+OPCODE(SUBI, BB) /* R(a) = R(a)-mrb_int(b) */
+OPCODE(MUL, B) /* R(a) = R(a)*R(a+1) */
+OPCODE(DIV, B) /* R(a) = R(a)/R(a+1) */
+OPCODE(EQ, B) /* R(a) = R(a)==R(a+1) */
+OPCODE(LT, B) /* R(a) = R(a)<R(a+1) */
+OPCODE(LE, B) /* R(a) = R(a)<=R(a+1) */
+OPCODE(GT, B) /* R(a) = R(a)>R(a+1) */
+OPCODE(GE, B) /* R(a) = R(a)>=R(a+1) */
+OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */
+OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */
+OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */
+OPCODE(ARYPUSH, BB) /* ary_push(R(a),R(a+1)..R(a+b)) */
+OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */
+OPCODE(AREF, BBB) /* R(a) = R(b)[c] */
+OPCODE(ASET, BBB) /* R(a)[c] = R(b) */
+OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+c) = R(a)[b..] */
+OPCODE(INTERN, B) /* R(a) = intern(R(a)) */
+OPCODE(SYMBOL, BB) /* R(a) = intern(Pool(b)) */
+OPCODE(STRING, BB) /* R(a) = str_dup(Pool(b)) */
+OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */
+OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b*2-1)) */
+OPCODE(HASHADD, BB) /* hash_push(R(a),R(a+1)..R(a+b*2)) */
+OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */
+OPCODE(LAMBDA, BB) /* R(a) = lambda(Irep(b),L_LAMBDA) */
+OPCODE(BLOCK, BB) /* R(a) = lambda(Irep(b),L_BLOCK) */
+OPCODE(METHOD, BB) /* R(a) = lambda(Irep(b),L_METHOD) */
+OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */
+OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */
+OPCODE(OCLASS, B) /* R(a) = ::Object */
+OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */
+OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */
+OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),Irep(b)) */
+OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)); R(a) = Syms(b) */
+OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */
+OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */
+OPCODE(SCLASS, B) /* R(a) = R(a).singleton_class */
+OPCODE(TCLASS, B) /* R(a) = target_class */
+OPCODE(DEBUG, BBB) /* print a,b,c */
+OPCODE(ERR, B) /* raise(LocalJumpError, Pool(a)) */
+OPCODE(EXT1, Z) /* make 1st operand (a) 16bit */
+OPCODE(EXT2, Z) /* make 2nd operand (b) 16bit */
+OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */
+OPCODE(STOP, Z) /* stop VM */
diff --git a/include/mruby/presym.h b/include/mruby/presym.h
new file mode 100644
index 000000000..066b675e7
--- /dev/null
+++ b/include/mruby/presym.h
@@ -0,0 +1,40 @@
+/**
+** @file mruby/presym.h - Preallocated Symbols
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_PRESYM_H
+#define MRUBY_PRESYM_H
+
+#if defined(MRB_NO_PRESYM)
+# include <mruby/presym/disable.h>
+#elif !defined(MRB_PRESYM_SCANNING)
+# include <mruby/presym/enable.h>
+#endif
+
+/*
+ * Where `mrb_intern_lit` is allowed for symbol interning, it is directly
+ * replaced by the symbol ID if presym is enabled by using the following
+ * macros.
+ *
+ * MRB_OPSYM(xor) //=> ^ (Operator)
+ * MRB_CVSYM(xor) //=> @@xor (Class Variable)
+ * MRB_IVSYM(xor) //=> @xor (Instance Variable)
+ * MRB_SYM_B(xor) //=> xor! (Method with Bang)
+ * MRB_SYM_Q(xor) //=> xor? (Method with Question mark)
+ * MRB_SYM_E(xor) //=> xor= (Method with Equal)
+ * MRB_SYM(xor) //=> xor (Word characters)
+ *
+ * For `MRB_OPSYM`, specify the names corresponding to operators (see
+ * `MRuby::Presym::OPERATORS` in `lib/mruby/presym.rb` for the names that
+ * can be specified for it). Other than that, describe only word characters
+ * excluding leading and ending punctuations.
+ *
+ * These macros are expanded to `mrb_intern_lit` if presym is disabled,
+ * therefore the mruby state variable is required. The above macros can be
+ * used when the variable name is `mrb`. If you want to use other variable
+ * names, you need to use macros with `_2` suffix, such as `MRB_SYM_2`.
+ */
+
+#endif /* MRUBY_PRESYM_H */
diff --git a/include/mruby/presym/disable.h b/include/mruby/presym/disable.h
new file mode 100644
index 000000000..45843fbf8
--- /dev/null
+++ b/include/mruby/presym/disable.h
@@ -0,0 +1,70 @@
+/**
+** @file mruby/presym/disable.h - Disable Preallocated Symbols
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_PRESYM_DISABLE_H
+#define MRUBY_PRESYM_DISABLE_H
+
+#include <string.h>
+
+#define MRB_PRESYM_MAX 0
+
+#define MRB_OPSYM(name) MRB_OPSYM__##name(mrb)
+#define MRB_CVSYM(name) mrb_intern_lit(mrb, "@@" #name)
+#define MRB_IVSYM(name) mrb_intern_lit(mrb, "@" #name)
+#define MRB_SYM_B(name) mrb_intern_lit(mrb, #name "!")
+#define MRB_SYM_Q(name) mrb_intern_lit(mrb, #name "?")
+#define MRB_SYM_E(name) mrb_intern_lit(mrb, #name "=")
+#define MRB_SYM(name) mrb_intern_lit(mrb, #name)
+
+#define MRB_OPSYM_2(mrb, name) MRB_OPSYM__##name(mrb)
+#define MRB_CVSYM_2(mrb, name) mrb_intern_lit(mrb, "@@" #name)
+#define MRB_IVSYM_2(mrb, name) mrb_intern_lit(mrb, "@" #name)
+#define MRB_SYM_B_2(mrb, name) mrb_intern_lit(mrb, #name "!")
+#define MRB_SYM_Q_2(mrb, name) mrb_intern_lit(mrb, #name "?")
+#define MRB_SYM_E_2(mrb, name) mrb_intern_lit(mrb, #name "=")
+#define MRB_SYM_2(mrb, name) mrb_intern_lit(mrb, #name)
+
+#define MRB_OPSYM__not(mrb) mrb_intern_lit(mrb, "!")
+#define MRB_OPSYM__mod(mrb) mrb_intern_lit(mrb, "%")
+#define MRB_OPSYM__and(mrb) mrb_intern_lit(mrb, "&")
+#define MRB_OPSYM__mul(mrb) mrb_intern_lit(mrb, "*")
+#define MRB_OPSYM__add(mrb) mrb_intern_lit(mrb, "+")
+#define MRB_OPSYM__sub(mrb) mrb_intern_lit(mrb, "-")
+#define MRB_OPSYM__div(mrb) mrb_intern_lit(mrb, "/")
+#define MRB_OPSYM__lt(mrb) mrb_intern_lit(mrb, "<")
+#define MRB_OPSYM__gt(mrb) mrb_intern_lit(mrb, ">")
+#define MRB_OPSYM__xor(mrb) mrb_intern_lit(mrb, "^")
+#define MRB_OPSYM__tick(mrb) mrb_intern_lit(mrb, "`")
+#define MRB_OPSYM__or(mrb) mrb_intern_lit(mrb, "|")
+#define MRB_OPSYM__neg(mrb) mrb_intern_lit(mrb, "~")
+#define MRB_OPSYM__neq(mrb) mrb_intern_lit(mrb, "!=")
+#define MRB_OPSYM__nmatch(mrb) mrb_intern_lit(mrb, "!~")
+#define MRB_OPSYM__andand(mrb) mrb_intern_lit(mrb, "&&")
+#define MRB_OPSYM__pow(mrb) mrb_intern_lit(mrb, "**")
+#define MRB_OPSYM__plus(mrb) mrb_intern_lit(mrb, "+@")
+#define MRB_OPSYM__minus(mrb) mrb_intern_lit(mrb, "-@")
+#define MRB_OPSYM__lshift(mrb) mrb_intern_lit(mrb, "<<")
+#define MRB_OPSYM__le(mrb) mrb_intern_lit(mrb, "<=")
+#define MRB_OPSYM__eq(mrb) mrb_intern_lit(mrb, "==")
+#define MRB_OPSYM__match(mrb) mrb_intern_lit(mrb, "=~")
+#define MRB_OPSYM__ge(mrb) mrb_intern_lit(mrb, ">=")
+#define MRB_OPSYM__rshift(mrb) mrb_intern_lit(mrb, ">>")
+#define MRB_OPSYM__aref(mrb) mrb_intern_lit(mrb, "[]")
+#define MRB_OPSYM__oror(mrb) mrb_intern_lit(mrb, "||")
+#define MRB_OPSYM__cmp(mrb) mrb_intern_lit(mrb, "<=>")
+#define MRB_OPSYM__eqq(mrb) mrb_intern_lit(mrb, "===")
+#define MRB_OPSYM__aset(mrb) mrb_intern_lit(mrb, "[]=")
+
+#define MRB_PRESYM_DEFINE_VAR_AND_INITER(name, size, ...) \
+ static mrb_sym name[size]; \
+ static void presym_init_##name(mrb_state *mrb) { \
+ mrb_sym name__[] = {__VA_ARGS__}; \
+ memcpy(name, name__, sizeof(name)); \
+ }
+
+#define MRB_PRESYM_INIT_SYMBOLS(mrb, name) presym_init_##name(mrb)
+
+#endif /* MRUBY_PRESYM_DISABLE_H */
diff --git a/include/mruby/presym/enable.h b/include/mruby/presym/enable.h
new file mode 100644
index 000000000..8ca0c3cc6
--- /dev/null
+++ b/include/mruby/presym/enable.h
@@ -0,0 +1,37 @@
+/**
+** @file mruby/presym/enable.h - Enable Preallocated Symbols
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_PRESYM_ENABLE_H
+#define MRUBY_PRESYM_ENABLE_H
+
+#include <mruby/presym/id.h>
+
+#define MRB_OPSYM(name) MRB_OPSYM__##name
+#define MRB_CVSYM(name) MRB_CVSYM__##name
+#define MRB_IVSYM(name) MRB_IVSYM__##name
+#define MRB_SYM_B(name) MRB_SYM_B__##name
+#define MRB_SYM_Q(name) MRB_SYM_Q__##name
+#define MRB_SYM_E(name) MRB_SYM_E__##name
+#define MRB_SYM(name) MRB_SYM__##name
+
+#define MRB_OPSYM_2(mrb, name) MRB_OPSYM__##name
+#define MRB_CVSYM_2(mrb, name) MRB_CVSYM__##name
+#define MRB_IVSYM_2(mrb, name) MRB_IVSYM__##name
+#define MRB_SYM_B_2(mrb, name) MRB_SYM_B__##name
+#define MRB_SYM_Q_2(mrb, name) MRB_SYM_Q__##name
+#define MRB_SYM_E_2(mrb, name) MRB_SYM_E__##name
+#define MRB_SYM_2(mrb, name) MRB_SYM__##name
+
+#define MRB_PRESYM_DEFINE_VAR_AND_INITER(name, size, ...) \
+ static const mrb_sym name[] = {__VA_ARGS__};
+
+#define MRB_PRESYM_INIT_SYMBOLS(mrb, name) (void)(mrb)
+
+/* use MRB_SYM() for E_RUNTIME_ERROR etc. */
+#undef MRB_ERROR_SYM
+#define MRB_ERROR_SYM(sym) MRB_SYM(sym)
+
+#endif /* MRUBY_PRESYM_ENABLE_H */
diff --git a/include/mruby/presym/scanning.h b/include/mruby/presym/scanning.h
new file mode 100644
index 000000000..fab0743f7
--- /dev/null
+++ b/include/mruby/presym/scanning.h
@@ -0,0 +1,73 @@
+/**
+** @file mruby/presym/scanning.h - Scanning Preallocated Symbols
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_PRESYM_SCANNING_H
+#define MRUBY_PRESYM_SCANNING_H
+
+#define MRB_PRESYM_SCANNING_TAGGED(arg) <@! arg !@>
+
+#undef mrb_intern_lit
+#define mrb_intern_lit(mrb, name) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_intern_cstr(mrb, name) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_method(mrb, c, name, f, a) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_class_method(mrb, c, name, f, a) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_singleton_method(mrb, c, name, f, a) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_class(mrb, name, s) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_class_under(mrb, o, name, s) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_module(mrb, name) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_module_under(mrb, o, name) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_module_function(mrb, c, name, f, s) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_const(mrb, c, name, v) MRB_PRESYM_SCANNING_TAGGED(name)
+#define mrb_define_global_const(mrb, name, v) MRB_PRESYM_SCANNING_TAGGED(name)
+
+#define MRB_OPSYM(name) MRB_OPSYM__##name(mrb)
+#define MRB_CVSYM(name) MRB_PRESYM_SCANNING_TAGGED("@@" #name)
+#define MRB_IVSYM(name) MRB_PRESYM_SCANNING_TAGGED("@" #name)
+#define MRB_SYM_B(name) MRB_PRESYM_SCANNING_TAGGED(#name "!")
+#define MRB_SYM_Q(name) MRB_PRESYM_SCANNING_TAGGED(#name "?")
+#define MRB_SYM_E(name) MRB_PRESYM_SCANNING_TAGGED(#name "=")
+#define MRB_SYM(name) MRB_PRESYM_SCANNING_TAGGED(#name)
+
+#define MRB_OPSYM_2(mrb, name) MRB_OPSYM__##name(mrb)
+#define MRB_CVSYM_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED("@@" #name)
+#define MRB_IVSYM_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED("@" #name)
+#define MRB_SYM_B_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED(#name "!")
+#define MRB_SYM_Q_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED(#name "?")
+#define MRB_SYM_E_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED(#name "=")
+#define MRB_SYM_2(mrb, name) MRB_PRESYM_SCANNING_TAGGED(#name)
+
+#define MRB_OPSYM__not(mrb) MRB_PRESYM_SCANNING_TAGGED("!")
+#define MRB_OPSYM__mod(mrb) MRB_PRESYM_SCANNING_TAGGED("%")
+#define MRB_OPSYM__and(mrb) MRB_PRESYM_SCANNING_TAGGED("&")
+#define MRB_OPSYM__mul(mrb) MRB_PRESYM_SCANNING_TAGGED("*")
+#define MRB_OPSYM__add(mrb) MRB_PRESYM_SCANNING_TAGGED("+")
+#define MRB_OPSYM__sub(mrb) MRB_PRESYM_SCANNING_TAGGED("-")
+#define MRB_OPSYM__div(mrb) MRB_PRESYM_SCANNING_TAGGED("/")
+#define MRB_OPSYM__lt(mrb) MRB_PRESYM_SCANNING_TAGGED("<")
+#define MRB_OPSYM__gt(mrb) MRB_PRESYM_SCANNING_TAGGED(">")
+#define MRB_OPSYM__xor(mrb) MRB_PRESYM_SCANNING_TAGGED("^")
+#define MRB_OPSYM__tick(mrb) MRB_PRESYM_SCANNING_TAGGED("`")
+#define MRB_OPSYM__or(mrb) MRB_PRESYM_SCANNING_TAGGED("|")
+#define MRB_OPSYM__neg(mrb) MRB_PRESYM_SCANNING_TAGGED("~")
+#define MRB_OPSYM__neq(mrb) MRB_PRESYM_SCANNING_TAGGED("!=")
+#define MRB_OPSYM__nmatch(mrb) MRB_PRESYM_SCANNING_TAGGED("!~")
+#define MRB_OPSYM__andand(mrb) MRB_PRESYM_SCANNING_TAGGED("&&")
+#define MRB_OPSYM__pow(mrb) MRB_PRESYM_SCANNING_TAGGED("**")
+#define MRB_OPSYM__plus(mrb) MRB_PRESYM_SCANNING_TAGGED("+@")
+#define MRB_OPSYM__minus(mrb) MRB_PRESYM_SCANNING_TAGGED("-@")
+#define MRB_OPSYM__lshift(mrb) MRB_PRESYM_SCANNING_TAGGED("<<")
+#define MRB_OPSYM__le(mrb) MRB_PRESYM_SCANNING_TAGGED("<=")
+#define MRB_OPSYM__eq(mrb) MRB_PRESYM_SCANNING_TAGGED("==")
+#define MRB_OPSYM__match(mrb) MRB_PRESYM_SCANNING_TAGGED("=~")
+#define MRB_OPSYM__ge(mrb) MRB_PRESYM_SCANNING_TAGGED(">=")
+#define MRB_OPSYM__rshift(mrb) MRB_PRESYM_SCANNING_TAGGED(">>")
+#define MRB_OPSYM__aref(mrb) MRB_PRESYM_SCANNING_TAGGED("[]")
+#define MRB_OPSYM__oror(mrb) MRB_PRESYM_SCANNING_TAGGED("||")
+#define MRB_OPSYM__cmp(mrb) MRB_PRESYM_SCANNING_TAGGED("<=>")
+#define MRB_OPSYM__eqq(mrb) MRB_PRESYM_SCANNING_TAGGED("===")
+#define MRB_OPSYM__aset(mrb) MRB_PRESYM_SCANNING_TAGGED("[]=")
+
+#endif /* MRUBY_PRESYM_SCANNING_H */
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 82b93ddef..31f40d379 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -1,5 +1,5 @@
-/*
-** mruby/proc.h - Proc class
+/**
+** @file mruby/proc.h - Proc class
**
** See Copyright Notice in mruby.h
*/
@@ -7,31 +7,48 @@
#ifndef MRUBY_PROC_H
#define MRUBY_PROC_H
-#include "mruby/irep.h"
+#include "common.h"
+#include <mruby/irep.h>
-#if defined(__cplusplus)
-extern "C" {
-#endif
+/**
+ * Proc class
+ */
+MRB_BEGIN_DECL
struct REnv {
MRB_OBJECT_HEADER;
mrb_value *stack;
+ struct mrb_context *cxt;
mrb_sym mid;
- ptrdiff_t cioff;
};
-#define MRB_ENV_STACK_LEN(e) ((e)->flags)
-#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1)
-#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0)
+/* flags (21bits): 1(close):1(touched):1(heap):8(cioff/bidx):8(stack_len) */
+#define MRB_ENV_SET_LEN(e,len) ((e)->flags = (((e)->flags & ~0xff)|((unsigned int)(len) & 0xff)))
+#define MRB_ENV_LEN(e) ((mrb_int)((e)->flags & 0xff))
+#define MRB_ENV_CLOSED (1<<20)
+#define MRB_ENV_TOUCHED (1<<19)
+#define MRB_ENV_HEAPED (1<<18)
+#define MRB_ENV_CLOSE(e) ((e)->flags |= MRB_ENV_CLOSED)
+#define MRB_ENV_TOUCH(e) ((e)->flags |= MRB_ENV_TOUCHED)
+#define MRB_ENV_HEAP(e) ((e)->flags |= MRB_ENV_HEAPED)
+#define MRB_ENV_HEAP_P(e) ((e)->flags & MRB_ENV_HEAPED)
+#define MRB_ENV_ONSTACK_P(e) (((e)->flags & MRB_ENV_CLOSED) == 0)
+#define MRB_ENV_BIDX(e) (((e)->flags >> 8) & 0xff)
+#define MRB_ENV_SET_BIDX(e,idx) ((e)->flags = (((e)->flags & ~(0xff<<8))|((unsigned int)(idx) & 0xff)<<8))
+
+void mrb_env_unshare(mrb_state*, struct REnv*);
struct RProc {
MRB_OBJECT_HEADER;
union {
- mrb_irep *irep;
+ const mrb_irep *irep;
mrb_func_t func;
} body;
- struct RClass *target_class;
- struct REnv *env;
+ const struct RProc *upper;
+ union {
+ struct RClass *target_class;
+ struct REnv *env;
+ } e;
};
/* aspec access */
@@ -40,34 +57,153 @@ struct RProc {
#define MRB_ASPEC_REST(a) (((a) >> 12) & 0x1)
#define MRB_ASPEC_POST(a) (((a) >> 7) & 0x1f)
#define MRB_ASPEC_KEY(a) (((a) >> 2) & 0x1f)
-#define MRB_ASPEC_KDICT(a) ((a) & (1<<1))
+#define MRB_ASPEC_KDICT(a) (((a) >> 1) & 0x1)
#define MRB_ASPEC_BLOCK(a) ((a) & 1)
-#define MRB_PROC_CFUNC 128
-#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC) != 0)
+#define MRB_PROC_CFUNC_FL 128
+#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC_FL) != 0)
+#define MRB_PROC_CFUNC(p) (p)->body.func
#define MRB_PROC_STRICT 256
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
+#define MRB_PROC_ORPHAN 512
+#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
+#define MRB_PROC_ENVSET 1024
+#define MRB_PROC_ENV_P(p) (((p)->flags & MRB_PROC_ENVSET) != 0)
+#define MRB_PROC_ENV(p) (MRB_PROC_ENV_P(p) ? (p)->e.env : NULL)
+#define MRB_PROC_TARGET_CLASS(p) (MRB_PROC_ENV_P(p) ? (p)->e.env->c : (p)->e.target_class)
+#define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\
+ if (MRB_PROC_ENV_P(p)) {\
+ (p)->e.env->c = (tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)(tc));\
+ }\
+ else {\
+ (p)->e.target_class = (tc);\
+ mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)(tc));\
+ }\
+} while (0)
+#define MRB_PROC_SCOPE 2048
+#define MRB_PROC_SCOPE_P(p) (((p)->flags & MRB_PROC_SCOPE) != 0)
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
-struct RProc *mrb_proc_new(mrb_state*, mrb_irep*);
-struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t);
-struct RProc *mrb_closure_new(mrb_state*, mrb_irep*);
-struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals);
+struct RProc *mrb_proc_new(mrb_state*, const mrb_irep*);
+struct RProc *mrb_closure_new(mrb_state*, const mrb_irep*);
+MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t);
+MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals);
void mrb_proc_copy(struct RProc *a, struct RProc *b);
-
-/* implementation of #send method */
-mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
+mrb_int mrb_proc_arity(const struct RProc *p);
/* following functions are defined in mruby-proc-ext so please include it when using */
-struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*);
-mrb_value mrb_cfunc_env_get(mrb_state*, mrb_int);
+MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv);
+MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx);
+/* old name */
+#define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx)
+
+#define MRB_METHOD_FUNC_FL 1
+#define MRB_METHOD_NOARG_FL 2
+
+#ifndef MRB_USE_METHOD_T_STRUCT
+
+#define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL)
+#define MRB_METHOD_NOARG_P(m) ((((uintptr_t)(m))&MRB_METHOD_NOARG_FL)?1:0)
+#define MRB_METHOD_NOARG_SET(m) ((m)=(mrb_method_t)(((uintptr_t)(m))|MRB_METHOD_NOARG_FL))
+#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)>>2))
+#define MRB_METHOD_FROM_FUNC(m,fn) ((m)=(mrb_method_t)((((uintptr_t)(fn))<<2)|MRB_METHOD_FUNC_FL))
+#define MRB_METHOD_FROM_PROC(m,pr) ((m)=(mrb_method_t)(pr))
+#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
+#define MRB_METHOD_PROC(m) ((struct RProc*)(m))
+#define MRB_METHOD_UNDEF_P(m) ((m)==0)
+
+#else
+
+#define MRB_METHOD_FUNC_P(m) ((m).flags&MRB_METHOD_FUNC_FL)
+#define MRB_METHOD_NOARG_P(m) (((m).flags&MRB_METHOD_NOARG_FL)?1:0)
+#define MRB_METHOD_FUNC(m) ((m).func)
+#define MRB_METHOD_NOARG_SET(m) do{(m).flags|=MRB_METHOD_NOARG_FL;}while(0)
+#define MRB_METHOD_FROM_FUNC(m,fn) do{(m).flags=MRB_METHOD_FUNC_FL;(m).func=(fn);}while(0)
+#define MRB_METHOD_FROM_PROC(m,pr) do{(m).flags=0;(m).proc=(struct RProc*)(pr);}while(0)
+#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
+#define MRB_METHOD_PROC(m) ((m).proc)
+#define MRB_METHOD_UNDEF_P(m) ((m).proc==NULL)
+
+#endif /* MRB_USE_METHOD_T_STRUCT */
+
+#define MRB_METHOD_CFUNC_P(m) (MRB_METHOD_FUNC_P(m)?TRUE:(MRB_METHOD_PROC(m)?(MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m))):FALSE))
+#define MRB_METHOD_CFUNC(m) (MRB_METHOD_FUNC_P(m)?MRB_METHOD_FUNC(m):((MRB_METHOD_PROC(m)&&MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m)))?MRB_PROC_CFUNC(MRB_METHOD_PROC(m)):NULL))
+
+
+#include <mruby/khash.h>
+
+MRB_API mrb_value mrb_load_proc(mrb_state *mrb, const struct RProc *proc);
+
+static inline void
+mrb_vm_ci_proc_set(mrb_callinfo *ci, const struct RProc *p)
+{
+ ci->proc = p;
+ ci->pc = (p && !MRB_PROC_CFUNC_P(p)) ? p->body.irep->iseq : NULL;
+}
+
+static inline struct RClass *
+mrb_vm_ci_target_class(const mrb_callinfo *ci)
+{
+ if (ci->u.env && ci->u.env->tt == MRB_TT_ENV) {
+ return ci->u.env->c;
+ }
+ else {
+ return ci->u.target_class;
+ }
+}
+
+static inline void
+mrb_vm_ci_target_class_set(mrb_callinfo *ci, struct RClass *tc)
+{
+ struct REnv *e = ci->u.env;
+ if (e) {
+ if (e->tt == MRB_TT_ENV) {
+ e->c = tc;
+ }
+ else {
+ ci->u.target_class = tc;
+ }
+ }
+}
+
+static inline struct REnv *
+mrb_vm_ci_env(const mrb_callinfo *ci)
+{
+ if (ci->u.env && ci->u.env->tt == MRB_TT_ENV) {
+ return ci->u.env;
+ }
+ else {
+ return NULL;
+ }
+}
-#include "mruby/khash.h"
-KHASH_DECLARE(mt, mrb_sym, struct RProc*, TRUE)
+static inline void
+mrb_vm_ci_env_set(mrb_callinfo *ci, struct REnv *e)
+{
+ if (ci->u.env) {
+ if (ci->u.env->tt == MRB_TT_ENV) {
+ if (e) {
+ e->c = ci->u.env->c;
+ ci->u.env = e;
+ }
+ else {
+ ci->u.target_class = ci->u.env->c;
+ }
+ }
+ else {
+ if (e) {
+ e->c = ci->u.target_class;
+ ci->u.env = e;
+ }
+ }
+ }
+ else {
+ ci->u.env = e;
+ }
+}
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
#endif /* MRUBY_PROC_H */
diff --git a/include/mruby/range.h b/include/mruby/range.h
index 61beb2319..fea700c24 100644
--- a/include/mruby/range.h
+++ b/include/mruby/range.h
@@ -1,5 +1,5 @@
-/*
-** mruby/range.h - Range class
+/**
+** @file mruby/range.h - Range class
**
** See Copyright Notice in mruby.h
*/
@@ -7,30 +7,73 @@
#ifndef MRUBY_RANGE_H
#define MRUBY_RANGE_H
-#if defined(__cplusplus)
-extern "C" {
+#include "common.h"
+
+/**
+ * Range class
+ */
+MRB_BEGIN_DECL
+
+#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT) || defined(MRB_WORD_BOXING)
+# define MRB_RANGE_EMBED
#endif
+#ifdef MRB_RANGE_EMBED
+struct RRange {
+ MRB_OBJECT_HEADER;
+ mrb_value beg;
+ mrb_value end;
+ mrb_bool excl;
+};
+# define mrb_gc_free_range(mrb, p) ((void)0)
+# define RANGE_BEG(p) ((p)->beg)
+# define RANGE_END(p) ((p)->end)
+#else
typedef struct mrb_range_edges {
mrb_value beg;
mrb_value end;
} mrb_range_edges;
-
struct RRange {
MRB_OBJECT_HEADER;
mrb_range_edges *edges;
- mrb_bool excl : 1;
+ mrb_bool excl;
};
+# define mrb_gc_free_range(mrb, p) mrb_free(mrb, (p)->edges)
+# define RANGE_BEG(p) ((p)->edges->beg)
+# define RANGE_END(p) ((p)->edges->end)
+#endif
+
+#define mrb_range_beg(mrb, r) RANGE_BEG(mrb_range_ptr(mrb, r))
+#define mrb_range_end(mrb, r) RANGE_END(mrb_range_ptr(mrb, r))
+#define mrb_range_excl_p(mrb, r) RANGE_EXCL(mrb_range_ptr(mrb, r))
+#define mrb_range_raw_ptr(r) ((struct RRange*)mrb_ptr(r))
+#define mrb_range_value(p) mrb_obj_value((void*)(p))
+#define RANGE_EXCL(p) ((p)->excl)
+
+MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range);
-#define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v)))
-#define mrb_range_value(p) mrb_obj_value((void*)(p))
+/*
+ * Initializes a Range.
+ *
+ * If the third parameter is FALSE then it includes the last value in the range.
+ * If the third parameter is TRUE then it excludes the last value in the range.
+ *
+ * @param start the beginning value.
+ * @param end the ending value.
+ * @param exclude represents the inclusion or exclusion of the last value.
+ */
+MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude);
+
+enum mrb_range_beg_len {
+ MRB_RANGE_TYPE_MISMATCH = 0, /* (failure) not range */
+ MRB_RANGE_OK = 1, /* (success) range */
+ MRB_RANGE_OUT = 2 /* (failure) out of range */
+};
-mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool);
-mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len);
+MRB_API enum mrb_range_beg_len 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));
+void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
#endif /* MRUBY_RANGE_H */
diff --git a/include/mruby/re.h b/include/mruby/re.h
index dfb3b0e2d..2d48019cf 100644
--- a/include/mruby/re.h
+++ b/include/mruby/re.h
@@ -1,5 +1,5 @@
-/*
-** mruby/re.h - Regexp class
+/**
+** @file mruby/re.h - Regexp class
**
** See Copyright Notice in mruby.h
*/
@@ -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 */
diff --git a/include/mruby/string.h b/include/mruby/string.h
index f8a1fa7bd..b296832af 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -1,5 +1,5 @@
-/*
-** mruby/string.h - String class
+/**
+** @file mruby/string.h - String class
**
** See Copyright Notice in mruby.h
*/
@@ -7,47 +7,62 @@
#ifndef MRUBY_STRING_H
#define MRUBY_STRING_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
+
+/**
+ * String class
+ */
+MRB_BEGIN_DECL
extern const char mrb_digitmap[];
-#define RSTRING_EMBED_LEN_MAX ((mrb_int)(sizeof(void*) * 3 - 1))
+#define RSTRING_EMBED_LEN_MAX \
+ ((mrb_int)(sizeof(void*) * 3 + sizeof(void*) - 32 / CHAR_BIT - 1))
struct RString {
MRB_OBJECT_HEADER;
union {
struct {
- mrb_int len;
+ mrb_ssize len;
union {
- mrb_int capa;
+ mrb_ssize capa;
struct mrb_shared_string *shared;
+ struct RString *fshared;
} aux;
char *ptr;
} heap;
- char ary[RSTRING_EMBED_LEN_MAX + 1];
} as;
};
+struct RStringEmbed {
+ MRB_OBJECT_HEADER;
+ char ary[RSTRING_EMBED_LEN_MAX+1];
+};
+
+#define RSTR_SET_TYPE_FLAG(s, type) (RSTR_UNSET_TYPE_FLAG(s), (s)->flags |= MRB_STR_##type)
+#define RSTR_UNSET_TYPE_FLAG(s) ((s)->flags &= ~(MRB_STR_TYPE_MASK|MRB_STR_EMBED_LEN_MASK))
#define RSTR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
#define RSTR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED)
#define RSTR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
#define RSTR_SET_EMBED_LEN(s, n) do {\
size_t tmp_n = (n);\
- s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
- s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
+ (s)->flags &= ~MRB_STR_EMBED_LEN_MASK;\
+ (s)->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
} while (0)
#define RSTR_SET_LEN(s, n) do {\
if (RSTR_EMBED_P(s)) {\
RSTR_SET_EMBED_LEN((s),(n));\
- } else {\
- s->as.heap.len = (mrb_int)(n);\
+ }\
+ else {\
+ (s)->as.heap.len = (mrb_ssize)(n);\
}\
} while (0)
+#define RSTR_EMBED_PTR(s) (((struct RStringEmbed*)(s))->ary)
#define RSTR_EMBED_LEN(s)\
(mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
-#define RSTR_PTR(s) ((RSTR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
+#define RSTR_EMBEDDABLE_P(len) ((len) <= RSTRING_EMBED_LEN_MAX)
+
+#define RSTR_PTR(s) ((RSTR_EMBED_P(s)) ? RSTR_EMBED_PTR(s) : (s)->as.heap.ptr)
#define RSTR_LEN(s) ((RSTR_EMBED_P(s)) ? RSTR_EMBED_LEN(s) : (s)->as.heap.len)
#define RSTR_CAPA(s) (RSTR_EMBED_P(s) ? RSTRING_EMBED_LEN_MAX : (s)->as.heap.aux.capa)
@@ -55,78 +70,379 @@ struct RString {
#define RSTR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
#define RSTR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
+#define RSTR_FSHARED_P(s) ((s)->flags & MRB_STR_FSHARED)
+#define RSTR_SET_FSHARED_FLAG(s) ((s)->flags |= MRB_STR_FSHARED)
+#define RSTR_UNSET_FSHARED_FLAG(s) ((s)->flags &= ~MRB_STR_FSHARED)
+
#define RSTR_NOFREE_P(s) ((s)->flags & MRB_STR_NOFREE)
#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE)
#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE)
+#ifdef MRB_UTF8_STRING
+# define RSTR_ASCII_P(s) ((s)->flags & MRB_STR_ASCII)
+# define RSTR_SET_ASCII_FLAG(s) ((s)->flags |= MRB_STR_ASCII)
+# define RSTR_UNSET_ASCII_FLAG(s) ((s)->flags &= ~MRB_STR_ASCII)
+# define RSTR_WRITE_ASCII_FLAG(s, v) (RSTR_UNSET_ASCII_FLAG(s), (s)->flags |= v)
+# define RSTR_COPY_ASCII_FLAG(dst, src) RSTR_WRITE_ASCII_FLAG(dst, RSTR_ASCII_P(src))
+#else
+# define RSTR_ASCII_P(s) (void)0
+# define RSTR_SET_ASCII_FLAG(s) (void)0
+# define RSTR_UNSET_ASCII_FLAG(s) (void)0
+# define RSTR_WRITE_ASCII_FLAG(s, v) (void)0
+# define RSTR_COPY_ASCII_FLAG(dst, src) (void)0
+#endif
+
+/**
+ * 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_LEN(s) RSTR_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))
-mrb_int mrb_str_strlen(mrb_state*, struct RString*);
+MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
+#define RSTRING_CSTR(mrb,s) mrb_string_cstr(mrb, s)
#define MRB_STR_SHARED 1
-#define MRB_STR_NOFREE 2
-#define MRB_STR_EMBED 4
-#define MRB_STR_EMBED_LEN_MASK 0xf8
-#define MRB_STR_EMBED_LEN_SHIFT 3
+#define MRB_STR_FSHARED 2
+#define MRB_STR_NOFREE 4
+#define MRB_STR_EMBED 8 /* type flags up to here */
+#define MRB_STR_ASCII 16
+#define MRB_STR_EMBED_LEN_SHIFT 6
+#define MRB_STR_EMBED_LEN_BIT 5
+#define MRB_STR_EMBED_LEN_MASK (((1 << MRB_STR_EMBED_LEN_BIT) - 1) << MRB_STR_EMBED_LEN_SHIFT)
+#define MRB_STR_TYPE_MASK 15
void mrb_gc_free_str(mrb_state*, struct RString*);
-void mrb_str_modify(mrb_state*, struct RString*);
-void mrb_str_concat(mrb_state*, mrb_value, mrb_value);
-mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value);
-mrb_value mrb_ptr_to_str(mrb_state *, void*);
-mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj);
-mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len);
-mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
-mrb_value mrb_string_type(mrb_state *mrb, mrb_value str);
-mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa);
-
-char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr);
-char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr);
-mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self);
-mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck);
-double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck);
-mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str);
-mrb_int mrb_str_hash(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str);
-mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2);
-mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len);
-mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr);
-mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2);
+
+MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s);
+/* mrb_str_modify() with keeping ASCII flag if set */
+MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s);
+
+/**
+ * Finds the index of a substring in a string
+ */
+MRB_API mrb_int mrb_str_index(mrb_state *mrb, mrb_value str, const char *p, mrb_int len, mrb_int offset);
+#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off);
+
+/**
+ * Appends self to other. Returns self as a concatenated string.
+ *
+ *
+ * Example:
+ *
+ * int
+ * main(int argc,
+ * char **argv)
+ * {
+ * // Variable declarations.
+ * mrb_value str1;
+ * mrb_value str2;
+ *
+ * mrb_state *mrb = mrb_open();
+ * if (!mrb)
+ * {
+ * // handle error
+ * }
+ *
+ * // Creates new Ruby strings.
+ * str1 = mrb_str_new_lit(mrb, "abc");
+ * str2 = mrb_str_new_lit(mrb, "def");
+ *
+ * // Concatenates str2 to str1.
+ * mrb_str_concat(mrb, str1, str2);
+ *
+ * // Prints new Concatenated Ruby string.
+ * mrb_p(mrb, str1);
+ *
+ * mrb_close(mrb);
+ * return 0;
+ * }
+ *
+ * Result:
+ *
+ * => "abcdef"
+ *
+ * @param mrb The current mruby state.
+ * @param self String to concatenate.
+ * @param other String to append to self.
+ * @return [mrb_value] Returns a new String appending other to self.
+ */
+MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other);
+
+/**
+ * Adds two strings together.
+ *
+ *
+ * Example:
+ *
+ * int
+ * main(int argc,
+ * char **argv)
+ * {
+ * // Variable declarations.
+ * mrb_value a;
+ * mrb_value b;
+ * mrb_value c;
+ *
+ * mrb_state *mrb = mrb_open();
+ * if (!mrb)
+ * {
+ * // handle error
+ * }
+ *
+ * // Creates two Ruby strings from the passed in C strings.
+ * a = mrb_str_new_lit(mrb, "abc");
+ * b = mrb_str_new_lit(mrb, "def");
+ *
+ * // Prints both C strings.
+ * mrb_p(mrb, a);
+ * mrb_p(mrb, b);
+ *
+ * // Concatenates both Ruby strings.
+ * c = mrb_str_plus(mrb, a, b);
+ *
+ * // Prints new Concatenated Ruby string.
+ * mrb_p(mrb, c);
+ *
+ * mrb_close(mrb);
+ * return 0;
+ * }
+ *
+ *
+ * Result:
+ *
+ * => "abc" # First string
+ * => "def" # Second string
+ * => "abcdef" # First & Second concatenated.
+ *
+ * @param mrb The current mruby state.
+ * @param a First string to concatenate.
+ * @param b Second string to concatenate.
+ * @return [mrb_value] Returns a new String containing a concatenated to b.
+ */
+MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b);
+
+/**
+ * Converts pointer into a Ruby string.
+ *
+ * @param mrb The current mruby state.
+ * @param p The pointer to convert to Ruby string.
+ * @return [mrb_value] Returns a new Ruby String.
+ */
+MRB_API mrb_value mrb_ptr_to_str(mrb_state *mrb, void *p);
+
+/**
+ * Returns an object as a Ruby string.
+ *
+ * @param mrb The current mruby state.
+ * @param obj An object to return as a Ruby string.
+ * @return [mrb_value] An object as a Ruby string.
+ */
+MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj);
+
+/**
+ * Resizes the string's length. Returns the amount of characters
+ * in the specified by len.
+ *
+ * Example:
+ *
+ * int
+ * main(int argc,
+ * char **argv)
+ * {
+ * // Variable declaration.
+ * mrb_value str;
+ *
+ * mrb_state *mrb = mrb_open();
+ * if (!mrb)
+ * {
+ * // handle error
+ * }
+ * // Creates a new string.
+ * str = mrb_str_new_lit(mrb, "Hello, world!");
+ * // Returns 5 characters of
+ * mrb_str_resize(mrb, str, 5);
+ * mrb_p(mrb, str);
+ *
+ * mrb_close(mrb);
+ * return 0;
+ * }
+ *
+ * Result:
+ *
+ * => "Hello"
+ *
+ * @param mrb The current mruby state.
+ * @param str The Ruby string to resize.
+ * @param len The length.
+ * @return [mrb_value] An object as a Ruby string.
+ */
+MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len);
+
+/**
+ * Returns a sub string.
+ *
+ * Example:
+ *
+ * int
+ * main(int argc,
+ * char const **argv)
+ * {
+ * // Variable declarations.
+ * mrb_value str1;
+ * mrb_value str2;
+ *
+ * mrb_state *mrb = mrb_open();
+ * if (!mrb)
+ * {
+ * // handle error
+ * }
+ * // Creates new string.
+ * 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);
+ *
+ * // Prints sub-string.
+ * mrb_p(mrb, str2);
+ *
+ * mrb_close(mrb);
+ * return 0;
+ * }
+ *
+ * Result:
+ *
+ * => "He"
+ *
+ * @param mrb The current mruby state.
+ * @param str Ruby string.
+ * @param beg The beginning point of the sub-string.
+ * @param len The end point of the sub-string.
+ * @return [mrb_value] An object as a Ruby sub-string.
+ */
+MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
+
+MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa);
+#define mrb_str_buf_new(mrb, capa) mrb_str_new_capa(mrb, (capa))
+
+/* NULL terminated C string from mrb_value */
+MRB_API const char *mrb_string_cstr(mrb_state *mrb, mrb_value str);
+/* NULL terminated C string from mrb_value; `str` will be updated */
+MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *str);
+/* obsolete: use RSTRING_PTR() */
+MRB_API const char *mrb_string_value_ptr(mrb_state *mrb, mrb_value str);
+/* obsolete: use RSTRING_LEN() */
+MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value str);
+
+/**
+ * Duplicates a string object.
+ *
+ *
+ * @param mrb The current mruby state.
+ * @param str Ruby string.
+ * @return [mrb_value] Duplicated Ruby string.
+ */
+MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str);
+
+/**
+ * Returns a symbol from a passed in Ruby string.
+ *
+ * @param mrb The current mruby state.
+ * @param self Ruby string.
+ * @return [mrb_value] A symbol.
+ */
+MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self);
+
+MRB_API mrb_value mrb_str_to_integer(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck);
+/* obsolete: use mrb_str_to_integer() */
+#define mrb_str_to_inum(mrb, str, base, badcheck) mrb_str_to_integer(mrb, str, base, badcheck)
+MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck);
+
+/**
+ * Returns true if the strings match and false if the strings don't match.
+ *
+ * @param mrb The current mruby state.
+ * @param str1 Ruby string to compare.
+ * @param str2 Ruby string to compare.
+ * @return [mrb_value] boolean value.
+ */
+MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2);
+
+/**
+ * Returns a concatenated string comprised of a Ruby string and a C string.
+ *
+ * @param mrb The current mruby state.
+ * @param str Ruby string.
+ * @param ptr A C string.
+ * @param len length of C string.
+ * @return [mrb_value] A Ruby string.
+ * @see mrb_str_cat_cstr
+ */
+MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len);
+
+/**
+ * Returns a concatenated string comprised of a Ruby string and a C string.
+ *
+ * @param mrb The current mruby state.
+ * @param str Ruby string.
+ * @param ptr A C string.
+ * @return [mrb_value] A Ruby string.
+ * @see mrb_str_cat
+ */
+MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr);
+MRB_API mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2);
#define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, lit, mrb_strlen_lit(lit))
-mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2);
-int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2);
-char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str);
-mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str);
+/**
+ * Adds str2 to the end of str1.
+ */
+MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2);
+
+/**
+ * Returns 0 if both Ruby strings are equal. Returns a value < 0 if Ruby str1 is less than Ruby str2. Returns a value > 0 if Ruby str2 is greater than Ruby str1.
+ */
+MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2);
+
+/**
+ * Returns a newly allocated C string from a Ruby string.
+ * This is an utility function to pass a Ruby string to C library functions.
+ *
+ * - Returned string does not contain any NUL characters (but terminator).
+ * - It raises an ArgumentError exception if Ruby string contains
+ * NUL characters.
+ * - Returned string will be freed automatically on next GC.
+ * - Caller can modify returned string without affecting Ruby string
+ * (e.g. it can be used for mkstemp(3)).
+ *
+ * @param mrb The current mruby state.
+ * @param str Ruby string. Must be an instance of String.
+ * @return [char *] A newly allocated C string.
+ */
+MRB_API char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str);
+
+uint32_t mrb_str_hash(mrb_state *mrb, mrb_value str);
+mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str);
+
+/**
+ * Returns a printable version of str, surrounded by quote marks, with special characters escaped.
+ */
+mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str);
/* For backward compatibility */
-static inline mrb_value
-mrb_str_cat2(mrb_state *mrb, mrb_value str, const char *ptr) {
- return mrb_str_cat_cstr(mrb, str, ptr);
-}
-
-static inline mrb_value
-mrb_str_buf_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
-{
- return mrb_str_cat(mrb, str, ptr, len);
-}
-
-static inline mrb_value
-mrb_str_buf_append(mrb_state *mrb, mrb_value str, mrb_value str2)
-{
- return mrb_str_cat_str(mrb, str, str2);
-}
-
-#if defined(__cplusplus)
-} /* extern "C" { */
+#define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr)
+#define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len)
+#define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2)
+
+mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp);
+mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
+
+#ifdef MRB_UTF8_STRING
+mrb_int mrb_utf8len(const char *str, const char *end);
+mrb_int mrb_utf8_strlen(const char *str, mrb_int byte_len);
#endif
+MRB_END_DECL
+
#endif /* MRUBY_STRING_H */
diff --git a/include/mruby/throw.h b/include/mruby/throw.h
new file mode 100644
index 000000000..52171e9b0
--- /dev/null
+++ b/include/mruby/throw.h
@@ -0,0 +1,66 @@
+/**
+** @file mruby/throw.h - mruby exception throwing handler
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRB_THROW_H
+#define MRB_THROW_H
+
+#if defined(MRB_USE_CXX_ABI)
+# if !defined(__cplusplus)
+# error Trying to use C++ exception handling in C code
+# endif
+#endif
+
+#if defined(MRB_USE_CXX_EXCEPTION)
+
+# if defined(__cplusplus)
+
+#define MRB_TRY(buf) try {
+#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; }
+#define MRB_END_EXC(buf) }
+
+#define MRB_THROW(buf) throw((buf)->impl)
+typedef mrb_int mrb_jmpbuf_impl;
+
+# else
+# error "need to be compiled with C++ compiler"
+# endif /* __cplusplus */
+
+#else
+
+#include <setjmp.h>
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#define MRB_SETJMP _setjmp
+#define MRB_LONGJMP _longjmp
+#elif defined(__MINGW64__) && defined(__GNUC__) && __GNUC__ >= 4
+#define MRB_SETJMP __builtin_setjmp
+#define MRB_LONGJMP __builtin_longjmp
+#else
+#define MRB_SETJMP setjmp
+#define MRB_LONGJMP longjmp
+#endif
+
+#define MRB_TRY(buf) if (MRB_SETJMP((buf)->impl) == 0) {
+#define MRB_CATCH(buf) } else {
+#define MRB_END_EXC(buf) }
+
+#define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1);
+#define mrb_jmpbuf_impl jmp_buf
+
+#endif
+
+struct mrb_jmpbuf {
+ mrb_jmpbuf_impl impl;
+
+#if defined(MRB_USE_CXX_EXCEPTION)
+ static mrb_int jmpbuf_id;
+# if defined(__cplusplus)
+ mrb_jmpbuf() : impl(jmpbuf_id++) {}
+# endif
+#endif
+};
+
+#endif /* MRB_THROW_H */
diff --git a/include/mruby/value.h b/include/mruby/value.h
index ae75f9c23..ad439334b 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -1,5 +1,5 @@
-/*
-** mruby/value.h - mruby value definitions
+/**
+** @file mruby/value.h - mruby value definitions
**
** See Copyright Notice in mruby.h
*/
@@ -7,94 +7,195 @@
#ifndef MRUBY_VALUE_H
#define MRUBY_VALUE_H
-typedef short mrb_sym;
+#include "common.h"
+
+/*
+ * MRuby Value definition functions and macros.
+ */
+MRB_BEGIN_DECL
+
+/**
+ * mruby Symbol.
+ * @class mrb_sym
+ *
+ * You can create an mrb_sym by simply using mrb_str_intern() or mrb_intern_cstr()
+ */
+typedef uint32_t mrb_sym;
+
+/**
+ * mruby Boolean.
+ * @class mrb_bool
+ *
+ *
+ * Used internally to represent boolean. Can be TRUE or FALSE.
+ * Not to be confused with Ruby's boolean classes, which can be
+ * obtained using mrb_false_value() and mrb_true_value()
+ */
+#if defined(__cplusplus) || (defined(__bool_true_false_are_defined) && __bool_true_false_are_defined)
+typedef bool mrb_bool;
+
+# ifndef FALSE
+# define FALSE false
+# endif
+# ifndef TRUE
+# define TRUE true
+# endif
+#else
+# if __STDC_VERSION__ >= 199901L
+typedef _Bool mrb_bool;
+# else
typedef uint8_t mrb_bool;
+# endif
+
+# ifndef FALSE
+# define FALSE 0
+# endif
+# ifndef TRUE
+# define TRUE 1
+# endif
+#endif
+
struct mrb_state;
-#if defined(MRB_INT16) && defined(MRB_INT64)
-# error "You can't define MRB_INT16 and MRB_INT64 at the same time."
+#if defined _MSC_VER && _MSC_VER < 1800
+# define PRIo64 "llo"
+# define PRId64 "lld"
+# define PRIu64 "llu"
+# define PRIx64 "llx"
+# define PRIo16 "ho"
+# define PRId16 "hd"
+# define PRIu16 "hu"
+# define PRIx16 "hx"
+# define PRIo32 "o"
+# define PRId32 "d"
+# define PRIu32 "u"
+# define PRIx32 "x"
+#else
+# include <inttypes.h>
#endif
#if defined(MRB_INT64)
typedef int64_t mrb_int;
+ typedef uint64_t mrb_uint;
# define MRB_INT_BIT 64
-# define MRB_INT_MIN (INT64_MIN>>MRB_FIXNUM_SHIFT)
-# define MRB_INT_MAX (INT64_MAX>>MRB_FIXNUM_SHIFT)
-#elif defined(MRB_INT16)
- typedef int16_t mrb_int;
-# define MRB_INT_BIT 16
-# define MRB_INT_MIN (INT16_MIN>>MRB_FIXNUM_SHIFT)
-# define MRB_INT_MAX )INT16_MAX>>MRB_FIXNUM_SHIFT)
+# define MRB_INT_MIN INT64_MIN
+# define MRB_INT_MAX INT64_MAX
+# define MRB_PRIo PRIo64
+# define MRB_PRId PRId64
+# define MRB_PRIx PRIx64
#else
typedef int32_t mrb_int;
+ typedef uint32_t mrb_uint;
# define MRB_INT_BIT 32
-# define MRB_INT_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT)
-# define MRB_INT_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT)
+# define MRB_INT_MIN INT32_MIN
+# define MRB_INT_MAX INT32_MAX
+# define MRB_PRIo PRIo32
+# define MRB_PRId PRId32
+# define MRB_PRIx PRIx32
#endif
-
-#ifdef MRB_USE_FLOAT
+
+#ifdef MRB_ENDIAN_BIG
+# define MRB_ENDIAN_LOHI(a,b) a b
+#else
+# define MRB_ENDIAN_LOHI(a,b) b a
+#endif
+
+MRB_API mrb_int mrb_int_read(const char *p, const char *e, char **endp);
+#ifndef MRB_NO_FLOAT
+MRB_API double mrb_float_read(const char*, char**);
+#ifdef MRB_USE_FLOAT32
typedef float mrb_float;
-# define mrb_float_to_str(buf, i) sprintf(buf, "%.7e", i)
-# define str_to_mrb_float(buf) strtof(buf, NULL)
#else
typedef double mrb_float;
-# define mrb_float_to_str(buf, i) sprintf(buf, "%.16e", i)
-# define str_to_mrb_float(buf) strtod(buf, NULL)
+#endif
#endif
-#ifdef _MSC_VER
-# ifndef __cplusplus
-# define inline __inline
-# endif
-# if _MSC_VER < 1900
-# define snprintf _snprintf
-# endif
-# if _MSC_VER < 1800
-# include <float.h>
+#if defined _MSC_VER && _MSC_VER < 1900
+MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg);
+MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...);
+# define vsnprintf(s, n, format, arg) mrb_msvc_vsnprintf(s, n, format, arg)
+# define snprintf(s, n, format, ...) mrb_msvc_snprintf(s, n, format, __VA_ARGS__)
+# if _MSC_VER < 1800 && !defined MRB_NO_FLOAT
# define isfinite(n) _finite(n)
# define isnan _isnan
# define isinf(n) (!_finite(n) && !_isnan(n))
# define signbit(n) (_copysign(1.0, (n)) < 0.0)
-# define strtoll _strtoi64
-# 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))
-# else
-# include <inttypes.h>
# endif
-#else
-# include <inttypes.h>
#endif
+#define MRB_VTYPE_FOREACH(f) \
+ /* mrb_vtype */ /* c type */ /* ruby class */ \
+ f(MRB_TT_FALSE, void, "false") \
+ f(MRB_TT_TRUE, void, "true") \
+ f(MRB_TT_SYMBOL, void, "Symbol") \
+ f(MRB_TT_UNDEF, void, "undefined") \
+ f(MRB_TT_FREE, void, "free") \
+ f(MRB_TT_FLOAT, struct RFloat, "Float") \
+ f(MRB_TT_INTEGER, struct RInteger, "Integer") \
+ f(MRB_TT_CPTR, struct RCptr, "cptr") \
+ f(MRB_TT_OBJECT, struct RObject, "Object") \
+ f(MRB_TT_CLASS, struct RClass, "Class") \
+ f(MRB_TT_MODULE, struct RClass, "Module") \
+ f(MRB_TT_ICLASS, struct RClass, "iClass") \
+ f(MRB_TT_SCLASS, struct RClass, "SClass") \
+ f(MRB_TT_PROC, struct RProc, "Proc") \
+ f(MRB_TT_ARRAY, struct RArray, "Array") \
+ f(MRB_TT_HASH, struct RHash, "Hash") \
+ f(MRB_TT_STRING, struct RString, "String") \
+ f(MRB_TT_RANGE, struct RRange, "Range") \
+ f(MRB_TT_EXCEPTION, struct RException, "Exception") \
+ f(MRB_TT_ENV, struct REnv, "env") \
+ f(MRB_TT_DATA, struct RData, "Data") \
+ f(MRB_TT_FIBER, struct RFiber, "Fiber") \
+ f(MRB_TT_STRUCT, struct RArray, "Struct") \
+ f(MRB_TT_ISTRUCT, struct RIStruct, "istruct") \
+ f(MRB_TT_BREAK, struct RBreak, "break") \
+ f(MRB_TT_COMPLEX, struct RComplex, "Complex") \
+ f(MRB_TT_RATIONAL, struct RRational, "Rational")
+
enum mrb_vtype {
- MRB_TT_FALSE = 0, /* 0 */
- MRB_TT_FREE, /* 1 */
- MRB_TT_TRUE, /* 2 */
- MRB_TT_FIXNUM, /* 3 */
- MRB_TT_SYMBOL, /* 4 */
- MRB_TT_UNDEF, /* 5 */
- MRB_TT_FLOAT, /* 6 */
- MRB_TT_CPTR, /* 7 */
- MRB_TT_OBJECT, /* 8 */
- MRB_TT_CLASS, /* 9 */
- MRB_TT_MODULE, /* 10 */
- MRB_TT_ICLASS, /* 11 */
- MRB_TT_SCLASS, /* 12 */
- MRB_TT_PROC, /* 13 */
- MRB_TT_ARRAY, /* 14 */
- MRB_TT_HASH, /* 15 */
- MRB_TT_STRING, /* 16 */
- MRB_TT_RANGE, /* 17 */
- MRB_TT_EXCEPTION, /* 18 */
- MRB_TT_FILE, /* 19 */
- MRB_TT_ENV, /* 20 */
- MRB_TT_DATA, /* 21 */
- MRB_TT_FIBER, /* 22 */
- MRB_TT_MAXDEFINE /* 23 */
+#define MRB_VTYPE_DEFINE(tt, type, name) tt,
+ MRB_VTYPE_FOREACH(MRB_VTYPE_DEFINE)
+#undef MRB_VTYPE_DEFINE
+ MRB_TT_MAXDEFINE
};
-#include "mruby/object.h"
+#define MRB_VTYPE_TYPEOF(tt) MRB_TYPEOF_##tt
+
+#define MRB_VTYPE_TYPEDEF(tt, type, name) typedef type MRB_VTYPE_TYPEOF(tt);
+MRB_VTYPE_FOREACH(MRB_VTYPE_TYPEDEF)
+#undef MRB_VTYPE_TYPEDEF
+
+/* for compatibility */
+#define MRB_TT_FIXNUM MRB_TT_INTEGER
+
+#include <mruby/object.h>
+
+#ifdef MRB_DOCUMENTATION_BLOCK
+
+/**
+ * @abstract
+ * MRuby value boxing.
+ *
+ * Actual implementation depends on configured boxing type.
+ *
+ * @see mruby/boxing_no.h Default boxing representation
+ * @see mruby/boxing_word.h Word representation
+ * @see mruby/boxing_nan.h Boxed double representation
+ */
+typedef void mrb_value;
+
+#endif
+
+#if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_64BIT))
+struct RCptr {
+ MRB_OBJECT_HEADER;
+ void *p;
+};
+#endif
#if defined(MRB_NAN_BOXING)
#include "boxing_nan.h"
@@ -104,8 +205,25 @@ enum mrb_vtype {
#include "boxing_no.h"
#endif
+#if INTPTR_MAX < MRB_INT_MAX
+ typedef intptr_t mrb_ssize;
+# define MRB_SSIZE_MAX INTPTR_MAX
+#else
+ typedef mrb_int mrb_ssize;
+# define MRB_SSIZE_MAX MRB_INT_MAX
+#endif
+
+#ifndef mrb_immediate_p
+#define mrb_immediate_p(o) (mrb_type(o) <= MRB_TT_CPTR)
+#endif
+#ifndef mrb_integer_p
+#define mrb_integer_p(o) (mrb_type(o) == MRB_TT_INTEGER)
+#endif
#ifndef mrb_fixnum_p
-#define mrb_fixnum_p(o) (mrb_type(o) == MRB_TT_FIXNUM)
+#define mrb_fixnum_p(o) mrb_integer_p(o)
+#endif
+#ifndef mrb_symbol_p
+#define mrb_symbol_p(o) (mrb_type(o) == MRB_TT_SYMBOL)
#endif
#ifndef mrb_undef_p
#define mrb_undef_p(o) (mrb_type(o) == MRB_TT_UNDEF)
@@ -113,29 +231,92 @@ enum mrb_vtype {
#ifndef mrb_nil_p
#define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o))
#endif
-#ifndef mrb_bool
-#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
+#ifndef mrb_false_p
+#define mrb_false_p(o) (mrb_type(o) == MRB_TT_FALSE && !!mrb_fixnum(o))
+#endif
+#ifndef mrb_true_p
+#define mrb_true_p(o) (mrb_type(o) == MRB_TT_TRUE)
#endif
+#ifndef MRB_NO_FLOAT
+#ifndef mrb_float_p
#define mrb_float_p(o) (mrb_type(o) == MRB_TT_FLOAT)
-#define mrb_symbol_p(o) (mrb_type(o) == MRB_TT_SYMBOL)
+#endif
+#endif
+#ifndef mrb_array_p
#define mrb_array_p(o) (mrb_type(o) == MRB_TT_ARRAY)
+#endif
+#ifndef mrb_string_p
#define mrb_string_p(o) (mrb_type(o) == MRB_TT_STRING)
+#endif
+#ifndef mrb_hash_p
#define mrb_hash_p(o) (mrb_type(o) == MRB_TT_HASH)
+#endif
+#ifndef mrb_cptr_p
#define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR)
+#endif
+#ifndef mrb_exception_p
#define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION)
+#endif
+#ifndef mrb_free_p
+#define mrb_free_p(o) (mrb_type(o) == MRB_TT_FREE)
+#endif
+#ifndef mrb_object_p
+#define mrb_object_p(o) (mrb_type(o) == MRB_TT_OBJECT)
+#endif
+#ifndef mrb_class_p
+#define mrb_class_p(o) (mrb_type(o) == MRB_TT_CLASS)
+#endif
+#ifndef mrb_module_p
+#define mrb_module_p(o) (mrb_type(o) == MRB_TT_MODULE)
+#endif
+#ifndef mrb_iclass_p
+#define mrb_iclass_p(o) (mrb_type(o) == MRB_TT_ICLASS)
+#endif
+#ifndef mrb_sclass_p
+#define mrb_sclass_p(o) (mrb_type(o) == MRB_TT_SCLASS)
+#endif
+#ifndef mrb_proc_p
+#define mrb_proc_p(o) (mrb_type(o) == MRB_TT_PROC)
+#endif
+#ifndef mrb_range_p
+#define mrb_range_p(o) (mrb_type(o) == MRB_TT_RANGE)
+#endif
+#ifndef mrb_env_p
+#define mrb_env_p(o) (mrb_type(o) == MRB_TT_ENV)
+#endif
+#ifndef mrb_data_p
+#define mrb_data_p(o) (mrb_type(o) == MRB_TT_DATA)
+#endif
+#ifndef mrb_fiber_p
+#define mrb_fiber_p(o) (mrb_type(o) == MRB_TT_FIBER)
+#endif
+#ifndef mrb_istruct_p
+#define mrb_istruct_p(o) (mrb_type(o) == MRB_TT_ISTRUCT)
+#endif
+#ifndef mrb_break_p
+#define mrb_break_p(o) (mrb_type(o) == MRB_TT_BREAK)
+#endif
+#ifndef mrb_bool
+#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
+#endif
#define mrb_test(o) mrb_bool(o)
-mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value);
-static inline mrb_value
-mrb_float_value(struct mrb_state *mrb, mrb_float f)
+/**
+ * Returns a float in Ruby.
+ *
+ * Takes a float and boxes it into an mrb_value
+ */
+#ifndef MRB_NO_FLOAT
+MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
{
mrb_value v;
(void) mrb;
SET_FLOAT_VALUE(mrb, v, f);
return v;
}
+#endif
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_cptr_value(struct mrb_state *mrb, void *p)
{
mrb_value v;
@@ -144,15 +325,24 @@ mrb_cptr_value(struct mrb_state *mrb, void *p)
return v;
}
-static inline mrb_value
-mrb_fixnum_value(mrb_int i)
+/**
+ * Returns an integer in Ruby.
+ */
+MRB_INLINE mrb_value mrb_int_value(struct mrb_state *mrb, mrb_int i)
{
mrb_value v;
- SET_INT_VALUE(v, i);
+ SET_INT_VALUE(mrb, v, i);
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i)
+{
+ mrb_value v;
+ SET_FIXNUM_VALUE(v, i);
+ return v;
+}
+
+MRB_INLINE mrb_value
mrb_symbol_value(mrb_sym i)
{
mrb_value v;
@@ -160,39 +350,50 @@ mrb_symbol_value(mrb_sym i)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
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;
}
-static inline mrb_value
-mrb_nil_value(void)
+/**
+ * Get a nil mrb_value object.
+ *
+ * @return
+ * nil mrb_value object reference.
+ */
+MRB_INLINE mrb_value mrb_nil_value(void)
{
mrb_value v;
SET_NIL_VALUE(v);
return v;
}
-static inline mrb_value
-mrb_false_value(void)
+/**
+ * Returns false in Ruby.
+ */
+MRB_INLINE mrb_value mrb_false_value(void)
{
mrb_value v;
SET_FALSE_VALUE(v);
return v;
}
-static inline mrb_value
-mrb_true_value(void)
+/**
+ * Returns true in Ruby.
+ */
+MRB_INLINE mrb_value mrb_true_value(void)
{
mrb_value v;
SET_TRUE_VALUE(v);
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_bool_value(mrb_bool boolean)
{
mrb_value v;
@@ -200,7 +401,7 @@ mrb_bool_value(mrb_bool boolean)
return v;
}
-static inline mrb_value
+MRB_INLINE mrb_value
mrb_undef_value(void)
{
mrb_value v;
@@ -208,4 +409,32 @@ mrb_undef_value(void)
return v;
}
+#if defined(MRB_USE_CUSTOM_RO_DATA_P)
+/* If you define `MRB_USE_CUSTOM_RO_DATA_P`, you must implement `mrb_ro_data_p()`. */
+mrb_bool mrb_ro_data_p(const char *p);
+#elif !defined(MRB_NO_DEFAULT_RO_DATA_P)
+#if defined(MRB_USE_ETEXT_RO_DATA_P)
+#define MRB_LINK_TIME_RO_DATA_P
+extern char etext, edata;
+static inline mrb_bool
+mrb_ro_data_p(const char *p)
+{
+ return &etext < p && p < &edata;
+}
+#elif defined(__APPLE__)
+#define MRB_LINK_TIME_RO_DATA_P
+#include <mach-o/getsect.h>
+static inline mrb_bool
+mrb_ro_data_p(const char *p)
+{
+ return (char*)get_etext() < p && p < (char*)get_edata();
+}
+#endif /* Linux or macOS */
+#endif /* MRB_NO_DEFAULT_RO_DATA_P */
+#ifndef MRB_LINK_TIME_RO_DATA_P
+# define mrb_ro_data_p(p) FALSE
+#endif
+
+MRB_END_DECL
+
#endif /* MRUBY_VALUE_H */
diff --git a/include/mruby/variable.h b/include/mruby/variable.h
index f3bf6ac8e..3dc2c9a6d 100644
--- a/include/mruby/variable.h
+++ b/include/mruby/variable.h
@@ -1,5 +1,5 @@
-/*
-** mruby/variable.h - mruby variables
+/**
+** @file mruby/variable.h - mruby variables
**
** See Copyright Notice in mruby.h
*/
@@ -7,63 +7,107 @@
#ifndef MRUBY_VARIABLE_H
#define MRUBY_VARIABLE_H
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "common.h"
-typedef struct global_variable {
- int counter;
- mrb_value *data;
- mrb_value (*getter)(void);
- void (*setter)(void);
- /* void (*marker)(); */
- /* int block_trace; */
- /* struct trace_var *trace; */
-} global_variable;
-
-struct global_entry {
- global_variable *var;
- mrb_sym id;
-};
+/**
+ * Functions to access mruby variables.
+ */
+MRB_BEGIN_DECL
mrb_value mrb_vm_special_get(mrb_state*, mrb_sym);
void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value);
-mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym);
-void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value);
mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym);
void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value);
mrb_value mrb_vm_const_get(mrb_state*, mrb_sym);
void mrb_vm_const_set(mrb_state*, mrb_sym, mrb_value);
-mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym);
-void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value);
-mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym);
-void mrb_const_remove(mrb_state*, mrb_value, mrb_sym);
+size_t mrb_obj_iv_tbl_memsize(mrb_value);
+MRB_API mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym);
+MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value);
+MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym);
+MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym);
+
+MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym sym);
+MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym sym);
+MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
+MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
+MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
+MRB_API mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym);
+MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v);
+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);
-mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
-void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
-mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
-void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
-mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym);
-void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v);
-mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym);
-mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym);
-void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src);
-mrb_bool mrb_const_defined_at(mrb_state *mrb, struct RClass *klass, mrb_sym id);
+/**
+ * Remove a global variable.
+ *
+ * Example:
+ *
+ * # Ruby style
+ * $value = nil
+ *
+ * // 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
+ */
+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);
+MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym);
+mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*);
+void mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod);
mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self);
-mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym);
-void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
-void mrb_gv_remove(mrb_state *mrb, mrb_sym sym);
mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value);
-mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*);
-mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer);
mrb_value mrb_mod_class_variables(mrb_state*, mrb_value);
mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym);
-mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym);
-void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v);
-void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v);
mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym);
-mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym);
+mrb_bool mrb_ident_p(const char *s, mrb_int len);
/* GC functions */
void mrb_gc_mark_gv(mrb_state*);
@@ -72,8 +116,10 @@ void mrb_gc_mark_iv(mrb_state*, struct RObject*);
size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*);
void mrb_gc_free_iv(mrb_state*, struct RObject*);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+/* return non zero to break the loop */
+typedef int (mrb_iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
+MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p);
+
+MRB_END_DECL
#endif /* MRUBY_VARIABLE_H */
diff --git a/include/mruby/version.h b/include/mruby/version.h
index d451dfb31..185263f32 100644
--- a/include/mruby/version.h
+++ b/include/mruby/version.h
@@ -1,34 +1,143 @@
+/**
+** @file mruby/version.h - mruby version definition
+**
+** See Copyright Notice in mruby.h
+*/
+
#ifndef MRUBY_VERSION_H
#define MRUBY_VERSION_H
-#define MRUBY_RUBY_VERSION "1.9"
+#include "common.h"
+
+/**
+ * mruby version definition macros
+ */
+MRB_BEGIN_DECL
+
+/*
+ * A passed in expression.
+ */
+#define MRB_STRINGIZE0(expr) #expr
+
+/*
+ * Passes in an expression to MRB_STRINGIZE0.
+ */
+#define MRB_STRINGIZE(expr) MRB_STRINGIZE0(expr)
+
+/*
+ * The version of Ruby used by mruby.
+ */
+#define MRUBY_RUBY_VERSION "3.0"
+
+/*
+ * Ruby engine.
+ */
#define MRUBY_RUBY_ENGINE "mruby"
-#define MRUBY_VERSION "1.0.0"
-#define MRUBY_RELEASE_MAJOR 1
+/*
+ * Major release version number.
+ */
+#define MRUBY_RELEASE_MAJOR 3
+
+/*
+ * Minor release version number.
+ */
#define MRUBY_RELEASE_MINOR 0
-#define MRUBY_RELEASE_TEENY 1
-#define MRUBY_RELEASE_NO 10001
-#define MRUBY_RELEASE_DATE "2014-01-10"
-#define MRUBY_RELEASE_YEAR 2014
-#define MRUBY_RELEASE_MONTH 1
-#define MRUBY_RELEASE_DAY 10
+/*
+ * Tiny release version number.
+ */
+#define MRUBY_RELEASE_TEENY 0
+
+/*
+ * Patch level.
+ */
+#define MRUBY_PATCHLEVEL -1
+
+/*
+ * Patch level string. (optional)
+ */
+#define MRUBY_PATCHLEVEL_STR ""
+
+#ifndef MRUBY_PATCHLEVEL_STR
+# if MRUBY_PATCHLEVEL < 0
+# define MRUBY_PATCHLEVEL_STR "dev"
+# else
+# define MRUBY_PATCHLEVEL_STR "p"MRB_STRINGIZE(MRUBY_PATCHLEVEL)
+# endif
+#endif
+
+/*
+ * The mruby version.
+ */
+#define MRUBY_VERSION MRB_STRINGIZE(MRUBY_RELEASE_MAJOR) "." MRB_STRINGIZE(MRUBY_RELEASE_MINOR) "." MRB_STRINGIZE(MRUBY_RELEASE_TEENY)
+
+/*
+ * Release number.
+ */
+#define MRUBY_RELEASE_NO (MRUBY_RELEASE_MAJOR * 100 * 100 + MRUBY_RELEASE_MINOR * 100 + MRUBY_RELEASE_TEENY)
+
+/*
+ * Release year.
+ */
+#define MRUBY_RELEASE_YEAR 2021
+
+/*
+ * Release month.
+ */
+#define MRUBY_RELEASE_MONTH 3
+
+/*
+ * Release day.
+ */
+#define MRUBY_RELEASE_DAY 5
+
+/*
+ * Release date as a string.
+ */
+#define MRUBY_RELEASE_DATE \
+ MRUBY_RELEASE_YEAR_STR "-" \
+ MRUBY_RELEASE_MONTH_STR "-" \
+ MRUBY_RELEASE_DAY_STR
+#define MRUBY_RELEASE_YEAR_STR MRB_STRINGIZE(MRUBY_RELEASE_YEAR)
+#if MRUBY_RELEASE_MONTH < 10
+#define MRUBY_RELEASE_MONTH_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_MONTH)
+#else
+#define MRUBY_RELEASE_MONTH_STR MRB_STRINGIZE(MRUBY_RELEASE_MONTH)
+#endif
+#if MRUBY_RELEASE_DAY < 10
+#define MRUBY_RELEASE_DAY_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_DAY)
+#else
+#define MRUBY_RELEASE_DAY_STR MRB_STRINGIZE(MRUBY_RELEASE_DAY)
+#endif
+
+/*
+ * The year mruby was first created.
+ */
#define MRUBY_BIRTH_YEAR 2010
+/*
+ * MRuby's authors.
+ */
#define MRUBY_AUTHOR "mruby developers"
-#define MRB_STRINGIZE0(expr) #expr
-#define MRB_STRINGIZE(expr) MRB_STRINGIZE0(expr)
-
-#define MRUBY_DESCRIPTION \
- "mruby " MRUBY_VERSION \
- " (" MRUBY_RELEASE_DATE ") " \
+/*
+ * mruby's version, and release date.
+ */
+#define MRUBY_DESCRIPTION \
+ "mruby " MRUBY_VERSION \
+ MRUBY_PATCHLEVEL_STR \
+ " (" MRUBY_RELEASE_DATE ")" \
+/*
+ * mruby's copyright information.
+ */
#define MRUBY_COPYRIGHT \
"mruby - Copyright (c) " \
MRB_STRINGIZE(MRUBY_BIRTH_YEAR)"-" \
MRB_STRINGIZE(MRUBY_RELEASE_YEAR)" " \
MRUBY_AUTHOR \
+MRB_END_DECL
+
#endif /* MRUBY_VERSION_H */