summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.c139
-rw-r--r--src/backtrace.c243
-rw-r--r--src/class.c786
-rw-r--r--src/codedump.c453
-rw-r--r--src/codegen.c3129
-rw-r--r--src/compar.c2
-rw-r--r--src/debug.c16
-rw-r--r--src/dump.c295
-rw-r--r--src/enum.c2
-rw-r--r--src/error.c115
-rw-r--r--src/error.h2
-rw-r--r--src/etc.c133
-rw-r--r--src/fmt_fp.c371
-rw-r--r--src/gc.c798
-rw-r--r--src/hash.c154
-rw-r--r--src/init.c7
-rw-r--r--src/kernel.c189
-rw-r--r--src/keywords50
-rw-r--r--src/lex.def212
-rw-r--r--src/load.c391
-rw-r--r--src/mrb_throw.h41
-rw-r--r--src/mruby_core.rake63
-rw-r--r--src/node.h117
-rw-r--r--src/numeric.c274
-rw-r--r--src/object.c65
-rw-r--r--src/opcode.h2
-rw-r--r--src/parse.y6370
-rw-r--r--src/pool.c15
-rw-r--r--src/print.c58
-rw-r--r--src/proc.c107
-rw-r--r--src/range.c26
-rw-r--r--src/state.c88
-rw-r--r--src/string.c1384
-rw-r--r--src/symbol.c146
-rw-r--r--src/value_array.h2
-rw-r--r--src/variable.c156
-rw-r--r--src/version.c8
-rw-r--r--src/vm.c353
38 files changed, 4077 insertions, 12685 deletions
diff --git a/src/array.c b/src/array.c
index d008e52cf..9b8a49584 100644
--- a/src/array.c
+++ b/src/array.c
@@ -4,25 +4,21 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/string.h"
-#include "mruby/range.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/range.h>
#include "value_array.h"
#define ARY_DEFAULT_LEN 4
#define ARY_SHRINK_RATIO 5 /* must be larger than 2 */
#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
#define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
-#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)
static inline mrb_value
ary_elt(mrb_value ary, mrb_int offset)
{
- if (RARRAY_LEN(ary) == 0) return mrb_nil_value();
if (offset < 0 || RARRAY_LEN(ary) <= offset) {
return mrb_nil_value();
}
@@ -51,14 +47,14 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
return a;
}
-mrb_value
+MRB_API mrb_value
mrb_ary_new_capa(mrb_state *mrb, mrb_int capa)
{
struct RArray *a = ary_new_capa(mrb, capa);
return mrb_obj_value(a);
}
-mrb_value
+MRB_API mrb_value
mrb_ary_new(mrb_state *mrb)
{
return mrb_ary_new_capa(mrb, 0);
@@ -88,21 +84,18 @@ array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
}
}
-mrb_value
+MRB_API mrb_value
mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
{
- mrb_value ary;
- struct RArray *a;
+ struct RArray *a = ary_new_capa(mrb, size);
- ary = mrb_ary_new_capa(mrb, size);
- a = mrb_ary_ptr(ary);
array_copy(a->ptr, vals, size);
a->len = size;
- return ary;
+ return mrb_obj_value(a);
}
-mrb_value
+MRB_API mrb_value
mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
{
struct RArray *a;
@@ -153,7 +146,7 @@ ary_modify(mrb_state *mrb, struct RArray *a)
}
}
-void
+MRB_API void
mrb_ary_modify(mrb_state *mrb, struct RArray* a)
{
mrb_write_barrier(mrb, (struct RBasic*)a);
@@ -200,10 +193,6 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
if (capa > a->aux.capa) {
mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
- if (!expanded_ptr) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "out of memory");
- }
-
a->aux.capa = capa;
a->ptr = expanded_ptr;
}
@@ -231,6 +220,28 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a)
}
}
+MRB_API mrb_value
+mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
+{
+ mrb_int old_len;
+ struct RArray *a = mrb_ary_ptr(ary);
+
+ ary_modify(mrb, a);
+ old_len = RARRAY_LEN(ary);
+ if (old_len != new_len) {
+ a->len = new_len;
+ if (new_len < old_len) {
+ ary_shrink_capa(mrb, a);
+ }
+ else {
+ ary_expand_capa(mrb, a, new_len);
+ ary_fill_with_nil(a->ptr + old_len, new_len - old_len);
+ }
+ }
+
+ return ary;
+}
+
static mrb_value
mrb_ary_s_create(mrb_state *mrb, mrb_value self)
{
@@ -254,7 +265,7 @@ ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen)
a->len = len;
}
-void
+MRB_API void
mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RArray *a2 = mrb_ary_ptr(other);
@@ -278,18 +289,19 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
{
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
- mrb_value ary;
mrb_value *ptr;
mrb_int blen;
mrb_get_args(mrb, "a", &ptr, &blen);
- ary = mrb_ary_new_capa(mrb, a1->len + blen);
- a2 = mrb_ary_ptr(ary);
+ if (ARY_MAX_SIZE - blen < a1->len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ a2 = ary_new_capa(mrb, a1->len + blen);
array_copy(a2->ptr, a1->ptr, a1->len);
array_copy(a2->ptr + a1->len, ptr, blen);
a2->len = a1->len + blen;
- return ary;
+ return mrb_obj_value(a2);
}
static void
@@ -303,7 +315,7 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
a->len = len;
}
-void
+MRB_API void
mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RArray *a2 = mrb_ary_ptr(other);
@@ -327,7 +339,6 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
{
struct RArray *a1 = mrb_ary_ptr(self);
struct RArray *a2;
- mrb_value ary;
mrb_value *ptr;
mrb_int times;
@@ -336,9 +347,10 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
}
if (times == 0) return mrb_ary_new(mrb);
-
- ary = mrb_ary_new_capa(mrb, a1->len * times);
- a2 = mrb_ary_ptr(ary);
+ if (ARY_MAX_SIZE / times < a1->len) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+ }
+ a2 = ary_new_capa(mrb, a1->len * times);
ptr = a2->ptr;
while (times--) {
array_copy(ptr, a1->ptr, a1->len);
@@ -346,7 +358,7 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
a2->len += a1->len;
}
- return ary;
+ return mrb_obj_value(a2);
}
static mrb_value
@@ -373,11 +385,8 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_ary_reverse(mrb_state *mrb, mrb_value self)
{
- struct RArray *a = mrb_ary_ptr(self), *b;
- mrb_value ary;
+ struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, a->len);
- ary = mrb_ary_new_capa(mrb, a->len);
- b = mrb_ary_ptr(ary);
if (a->len > 0) {
mrb_value *p1, *p2, *e;
@@ -389,10 +398,10 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self)
}
b->len = a->len;
}
- return ary;
+ return mrb_obj_value(b);
}
-void
+MRB_API void
mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -418,7 +427,7 @@ mrb_ary_push_m(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+MRB_API mrb_value
mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -429,7 +438,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary)
#define ARY_SHIFT_SHARED_MIN 10
-mrb_value
+MRB_API mrb_value
mrb_ary_shift(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -465,7 +474,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
item = 0
self.unshift item
p self #=> [0, 1, 2, 3] */
-mrb_value
+MRB_API mrb_value
mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
{
struct RArray *a = mrb_ary_ptr(self);
@@ -518,7 +527,7 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
return self;
}
-mrb_value
+MRB_API mrb_value
mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -530,7 +539,7 @@ mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n)
return a->ptr[n];
}
-void
+MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
struct RArray *a = mrb_ary_ptr(ary);
@@ -554,12 +563,12 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
-mrb_value
+MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
mrb_int tail, size;
- mrb_value *argv;
+ const mrb_value *argv;
mrb_int i, argc;
ary_modify(mrb, a);
@@ -643,10 +652,14 @@ aget_index(mrb_state *mrb, mrb_value index)
if (mrb_fixnum_p(index)) {
return mrb_fixnum(index);
}
+ else if (mrb_float_p(index)) {
+ return (mrb_int)mrb_float(index);
+ }
else {
- mrb_int i;
+ mrb_int i, argc;
+ mrb_value *argv;
- mrb_get_args(mrb, "i", &i);
+ mrb_get_args(mrb, "i*", &i, &argv, &argc);
return i;
}
}
@@ -875,7 +888,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
-mrb_value
+MRB_API mrb_value
mrb_ary_splat(mrb_state *mrb, mrb_value v)
{
if (mrb_array_p(v)) {
@@ -897,15 +910,20 @@ mrb_ary_size(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(a->len);
}
-mrb_value
+MRB_API mrb_value
mrb_ary_clear(mrb_state *mrb, mrb_value self)
{
struct RArray *a = mrb_ary_ptr(self);
- ary_modify(mrb, a);
+ if (ARY_SHARED_P(a)) {
+ mrb_ary_decref(mrb, a->aux.shared);
+ ARY_UNSET_SHARED_FLAG(a);
+ }
+ else {
+ mrb_free(mrb, a->ptr);
+ }
a->len = 0;
a->aux.capa = 0;
- mrb_free(mrb, a->ptr);
a->ptr = 0;
return self;
@@ -919,13 +937,13 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
return mrb_bool_value(a->len == 0);
}
-mrb_value
+MRB_API mrb_value
mrb_check_array_type(mrb_state *mrb, mrb_value ary)
{
return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
}
-mrb_value
+MRB_API mrb_value
mrb_ary_entry(mrb_value ary, mrb_int offset)
{
if (offset < 0) {
@@ -989,7 +1007,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
return result;
}
-mrb_value
+MRB_API mrb_value
mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
{
sep = mrb_obj_as_string(mrb, sep);
@@ -1012,7 +1030,7 @@ mrb_ary_join_m(mrb_state *mrb, mrb_value ary)
{
mrb_value sep = mrb_nil_value();
- mrb_get_args(mrb, "|S", &sep);
+ mrb_get_args(mrb, "|S!", &sep);
return mrb_ary_join(mrb, ary, sep);
}
@@ -1023,7 +1041,6 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
mrb_get_args(mrb, "o", &ary2);
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
- if (mrb_special_const_p(ary2)) return mrb_false_value();
if (!mrb_array_p(ary2)) {
return mrb_false_value();
}
@@ -1039,7 +1056,6 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
mrb_get_args(mrb, "o", &ary2);
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0);
- if (mrb_special_const_p(ary2)) return mrb_nil_value();
if (!mrb_array_p(ary2)) {
return mrb_nil_value();
}
@@ -1052,7 +1068,7 @@ mrb_init_array(mrb_state *mrb)
{
struct RClass *a;
- a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
+ mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */
MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
@@ -1084,5 +1100,6 @@ mrb_init_array(mrb_state *mrb)
mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */
}
diff --git a/src/backtrace.c b/src/backtrace.c
index 1e1f9fa1a..80a5e2935 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -4,137 +4,158 @@
** See Copyright Notice in mruby.h
*/
-#include <stdarg.h>
-#include "mruby.h"
-#include "mruby/variable.h"
-#include "mruby/proc.h"
-#include "mruby/array.h"
-#include "mruby/string.h"
-#include "mruby/class.h"
-#include "mruby/debug.h"
-#include "mruby/error.h"
-
-#ifdef ENABLE_STDIO
-
-typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...);
+#include <mruby.h>
+#include <mruby/variable.h>
+#include <mruby/proc.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+#include <mruby/debug.h>
+#include <mruby/error.h>
+#include <mruby/numeric.h>
+
+struct backtrace_location {
+ int i;
+ int lineno;
+ const char *filename;
+ const char *method;
+ const char *sep;
+ const char *class_name;
+};
+
+typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
+
+#ifndef MRB_DISABLE_STDIO
+
+struct print_backtrace_args {
+ FILE *stream;
+ int tracehead;
+};
static void
-print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...)
+print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
{
- va_list ap;
+ struct print_backtrace_args *args;
- va_start(ap, format);
- vfprintf((FILE*)stream, format, ap);
- va_end(ap);
-}
+ args = (struct print_backtrace_args*)data;
+
+ if (args->tracehead) {
+ fprintf(args->stream, "trace:\n");
+ args->tracehead = FALSE;
+ }
+
+ fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno);
+
+ if (loc->method) {
+ if (loc->class_name) {
+ fprintf(args->stream, ":in %s%s%s", loc->class_name, loc->sep, loc->method);
+ }
+ else {
+ fprintf(args->stream, ":in %s", loc->method);
+ }
+ }
+ fprintf(args->stream, "\n");
+}
-#define MIN_BUFSIZE 127
+#endif
static void
-get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...)
+get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
{
- va_list ap;
mrb_value ary, str;
int ai;
- if (level > 0) {
- return;
- }
-
ai = mrb_gc_arena_save(mrb);
- ary = mrb_obj_value((struct RArray*)stream);
+ ary = mrb_obj_value((struct RArray*)data);
- va_start(ap, format);
- str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1);
- va_end(ap);
+ str = mrb_str_new_cstr(mrb, loc->filename);
+ mrb_str_cat_lit(mrb, str, ":");
+ mrb_str_concat(mrb, str, mrb_fixnum_to_str(mrb, mrb_fixnum_value(loc->lineno), 10));
- va_start(ap, format);
- vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap);
- va_end(ap);
+ if (loc->method) {
+ mrb_str_cat_lit(mrb, str, ":in ");
+
+ if (loc->class_name) {
+ mrb_str_cat_cstr(mrb, str, loc->class_name);
+ mrb_str_cat_cstr(mrb, str, loc->sep);
+ }
+
+ mrb_str_cat_cstr(mrb, str, loc->method);
+ }
- mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1);
mrb_ary_push(mrb, ary, str);
mrb_gc_arena_restore(mrb, ai);
}
static void
-output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream)
+output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
{
- mrb_callinfo *ci;
- const char *filename, *method, *sep;
- int i, lineno, tracehead = 1;
+ int i;
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
for (i = ciidx; i >= 0; i--) {
+ struct backtrace_location loc;
+ mrb_callinfo *ci;
+ mrb_irep *irep;
+ mrb_code *pc;
+
ci = &mrb->c->cibase[i];
- filename = NULL;
if (!ci->proc) continue;
- if (MRB_PROC_CFUNC_P(ci->proc)) {
- continue;
+ if (MRB_PROC_CFUNC_P(ci->proc)) continue;
+
+ irep = ci->proc->body.irep;
+
+ if (mrb->c->cibase[i].err) {
+ pc = mrb->c->cibase[i].err;
}
- else {
- mrb_irep *irep = ci->proc->body.irep;
- mrb_code *pc;
-
- if (mrb->c->cibase[i].err) {
- pc = mrb->c->cibase[i].err;
- }
- else if (i+1 <= ciidx) {
- pc = mrb->c->cibase[i+1].pc - 1;
- }
- else {
- pc = pc0;
- }
- filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
- lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
+ else if (i+1 <= ciidx) {
+ pc = mrb->c->cibase[i+1].pc - 1;
}
- if (lineno == -1) continue;
- if (ci->target_class == ci->proc->target_class)
- sep = ".";
- else
- sep = "#";
-
- if (!filename) {
- filename = "(unknown)";
+ else {
+ pc = pc0;
}
+ loc.filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
+ loc.lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
- if (tracehead) {
- func(mrb, stream, 1, "trace:\n");
- tracehead = 0;
- }
- method = mrb_sym2name(mrb, ci->mid);
- if (method) {
- const char *cn = mrb_class_name(mrb, ci->proc->target_class);
-
- if (cn) {
- func(mrb, stream, 1, "\t[%d] ", i);
- func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method);
- func(mrb, stream, 1, "\n");
- }
- else {
- func(mrb, stream, 1, "\t[%d] ", i);
- func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method);
- func(mrb, stream, 1, "\n");
- }
+ if (loc.lineno == -1) continue;
+
+ if (ci->target_class == ci->proc->target_class) {
+ loc.sep = ".";
}
else {
- func(mrb, stream, 1, "\t[%d] ", i);
- func(mrb, stream, 0, "%s:%d", filename, lineno);
- func(mrb, stream, 1, "\n");
+ loc.sep = "#";
}
+
+ if (!loc.filename) {
+ loc.filename = "(unknown)";
+ }
+
+ loc.method = mrb_sym2name(mrb, ci->mid);
+ loc.class_name = mrb_class_name(mrb, ci->proc->target_class);
+ loc.i = i;
+ func(mrb, &loc, data);
}
}
static void
exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
{
+ mrb_value lastpc;
+ mrb_code *code;
+
+ lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"));
+ if (mrb_nil_p(lastpc)) {
+ code = NULL;
+ } else {
+ code = (mrb_code*)mrb_cptr(lastpc);
+ }
+
output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))),
- (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))),
- func, stream);
+ code, func, stream);
}
/* mrb_print_backtrace/mrb_get_backtrace:
@@ -144,13 +165,32 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
overwritten. So invoke these functions just after detecting exceptions.
*/
-void
+#ifndef MRB_DISABLE_STDIO
+
+MRB_API void
mrb_print_backtrace(mrb_state *mrb)
{
- exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr);
+ struct print_backtrace_args args;
+
+ if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
+ return;
+ }
+
+ args.stream = stderr;
+ args.tracehead = TRUE;
+ exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
}
-mrb_value
+#else
+
+MRB_API void
+mrb_print_backtrace(mrb_state *mrb)
+{
+}
+
+#endif
+
+MRB_API mrb_value
mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
{
mrb_value ary;
@@ -161,7 +201,7 @@ mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
return ary;
}
-mrb_value
+MRB_API mrb_value
mrb_get_backtrace(mrb_state *mrb)
{
mrb_value ary;
@@ -175,24 +215,3 @@ mrb_get_backtrace(mrb_state *mrb)
return ary;
}
-
-#else
-
-void
-mrb_print_backtrace(mrb_state *mrb)
-{
-}
-
-mrb_value
-mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
-{
- return mrb_ary_new(mrb);
-}
-
-mrb_value
-mrb_get_backtrace(mrb_state *mrb)
-{
- return mrb_ary_new(mrb);
-}
-
-#endif
diff --git a/src/class.c b/src/class.c
index ba078911b..ccbbe2544 100644
--- a/src/class.c
+++ b/src/class.c
@@ -4,17 +4,16 @@
** See Copyright Notice in mruby.h
*/
-#include <ctype.h>
#include <stdarg.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/numeric.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/error.h"
-#include "mruby/data.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/data.h>
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
@@ -77,7 +76,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
if (o->c->tt == MRB_TT_SCLASS) return;
sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
- sc->mt = 0;
+ sc->mt = kh_init(mt, mrb);
sc->iv = 0;
if (o->tt == MRB_TT_CLASS) {
c = (struct RClass*)o;
@@ -122,22 +121,35 @@ module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
return mrb_class_ptr(c);
}
-struct RClass*
+MRB_API struct RClass*
mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
{
mrb_value outer;
outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
- if (mrb_nil_p(outer)) return 0;
+ if (mrb_nil_p(outer)) return NULL;
return mrb_class_ptr(outer);
}
+static void
+check_if_class_or_module(mrb_state *mrb, mrb_value obj)
+{
+ switch (mrb_type(obj)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_MODULE:
+ return;
+ default:
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj));
+ }
+}
+
static struct RClass*
define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer)
{
struct RClass *m;
- if (mrb_const_defined_at(mrb, outer, name)) {
+ if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
return module_from_sym(mrb, outer, name);
}
m = mrb_module_new(mrb);
@@ -146,25 +158,26 @@ define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer)
return m;
}
-struct RClass*
+MRB_API struct RClass*
mrb_define_module_id(mrb_state *mrb, mrb_sym name)
{
return define_module(mrb, name, mrb->object_class);
}
-struct RClass*
+MRB_API struct RClass*
mrb_define_module(mrb_state *mrb, const char *name)
{
return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class);
}
-struct RClass*
+MRB_API struct RClass*
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
+ check_if_class_or_module(mrb, outer);
return define_module(mrb, id, mrb_class_ptr(outer));
}
-struct RClass *
+MRB_API struct RClass*
mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
mrb_sym id = mrb_intern_cstr(mrb, name);
@@ -175,12 +188,20 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
}
static struct RClass*
+find_origin(struct RClass *c)
+{
+ MRB_CLASS_ORIGIN(c);
+ return c;
+}
+
+static struct RClass*
define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer)
{
struct RClass * c;
- if (mrb_const_defined_at(mrb, outer, name)) {
+ if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
c = class_from_sym(mrb, outer, name);
+ MRB_CLASS_ORIGIN(c);
if (super && mrb_class_real(c->super) != super) {
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
mrb_sym2str(mrb, name),
@@ -195,16 +216,16 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
return c;
}
-struct RClass*
+MRB_API struct RClass*
mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super)
{
if (!super) {
- mrb_warn(mrb, "no super class for `%S', Object assumed", mrb_sym2str(mrb, name));
+ mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name));
}
return define_class(mrb, name, super, mrb->object_class);
}
-struct RClass*
+MRB_API struct RClass*
mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
{
return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
@@ -218,7 +239,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
}
-struct RClass*
+MRB_API struct RClass*
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
struct RClass *s;
@@ -233,22 +254,14 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id
else {
s = 0;
}
- switch (mrb_type(outer)) {
- case MRB_TT_CLASS:
- case MRB_TT_SCLASS:
- case MRB_TT_MODULE:
- break;
- default:
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", outer);
- break;
- }
+ check_if_class_or_module(mrb, outer);
c = define_class(mrb, id, s, mrb_class_ptr(outer));
mrb_class_inherited(mrb, mrb_class_real(c->super), c);
return c;
}
-mrb_bool
+MRB_API mrb_bool
mrb_class_defined(mrb_state *mrb, const char *name)
{
mrb_value sym = mrb_check_intern_cstr(mrb, name);
@@ -258,25 +271,25 @@ mrb_class_defined(mrb_state *mrb, const char *name)
return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym));
}
-struct RClass *
+MRB_API struct RClass *
mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
}
-struct RClass *
+MRB_API struct RClass *
mrb_class_get(mrb_state *mrb, const char *name)
{
return mrb_class_get_under(mrb, mrb->object_class, name);
}
-struct RClass *
+MRB_API struct RClass *
mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
}
-struct RClass *
+MRB_API struct RClass *
mrb_module_get(mrb_state *mrb, const char *name)
{
return mrb_module_get_under(mrb, mrb->object_class, name);
@@ -298,7 +311,7 @@ mrb_module_get(mrb_state *mrb, const char *name)
* \note if a class named \a name is already defined and its superclass is
* \a super, the function just returns the defined class.
*/
-struct RClass *
+MRB_API struct RClass *
mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
{
mrb_sym id = mrb_intern_cstr(mrb, name);
@@ -306,7 +319,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
#if 0
if (!super) {
- mrb_warn(mrb, "no super class for `%S::%S', Object assumed",
+ mrb_warn(mrb, "no super class for '%S::%S', Object assumed",
mrb_obj_value(outer), mrb_sym2str(mrb, id));
}
#endif
@@ -315,11 +328,13 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
return c;
}
-void
+MRB_API void
mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p)
{
- khash_t(mt) *h = c->mt;
+ khash_t(mt) *h;
khiter_t k;
+ MRB_CLASS_ORIGIN(c);
+ h = c->mt;
if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid);
@@ -329,7 +344,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
}
}
-void
+MRB_API void
mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec)
{
struct RProc *p;
@@ -341,28 +356,37 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f
mrb_gc_arena_restore(mrb, ai);
}
-void
+MRB_API void
mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
{
mrb_define_method_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec);
}
-void
-mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value body)
+/* a function to raise NotImplementedError with current method name */
+MRB_API void
+mrb_notimplement(mrb_state *mrb)
{
- khash_t(mt) *h = c->mt;
- khiter_t k;
- struct RProc *p;
+ const char *str;
+ mrb_int len;
+ mrb_callinfo *ci = mrb->c->ci;
- if (!h) h = c->mt = kh_init(mt, mrb);
- k = kh_put(mt, mrb, h, name);
- p = mrb_proc_ptr(body);
- kh_value(h, k) = p;
- if (p) {
- mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
+ if (ci->mid) {
+ str = mrb_sym2name_len(mrb, ci->mid, &len);
+ mrb_raisef(mrb, E_NOTIMP_ERROR,
+ "%S() function is unimplemented on this machine",
+ mrb_str_new_static(mrb, str, (size_t)len));
}
}
+/* a function to be replacement of unimplemented method */
+MRB_API mrb_value
+mrb_notimplement_m(mrb_state *mrb, mrb_value self)
+{
+ mrb_notimplement(mrb);
+ /* not reached */
+ return mrb_nil_value();
+}
+
static mrb_value
check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m)
{
@@ -393,6 +417,21 @@ to_hash(mrb_state *mrb, mrb_value val)
return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash");
}
+static mrb_sym
+to_sym(mrb_state *mrb, mrb_value ss)
+{
+ if (mrb_type(ss) == MRB_TT_SYMBOL) {
+ return mrb_symbol(ss);
+ }
+ else if (mrb_string_p(ss)) {
+ return mrb_intern_str(mrb, to_str(mrb, ss));
+ }
+ else {
+ mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
+ }
+}
+
/*
retrieve arguments from mrb_state.
@@ -406,12 +445,12 @@ to_hash(mrb_state *mrb, mrb_value val)
----------------------------------------------------------------------------------------------
o: Object [mrb_value]
C: class/module [mrb_value]
- S: String [mrb_value]
- A: Array [mrb_value]
- H: Hash [mrb_value]
- s: String [char*,mrb_int] Receive two arguments.
- z: String [char*] NUL terminated string.
- a: Array [mrb_value*,mrb_int] Receive two arguments.
+ S: String [mrb_value] when ! follows, the value may be nil
+ A: Array [mrb_value] when ! follows, the value may be nil
+ H: Hash [mrb_value] when ! follows, the value may be nil
+ s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil
+ z: String [char*] NUL terminated string; z! gives NULL for nil
+ a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil
f: Float [mrb_float]
i: Integer [mrb_int]
b: Boolean [mrb_bool]
@@ -422,7 +461,7 @@ to_hash(mrb_state *mrb, mrb_value val)
|: optional Next argument of '|' and later are optional.
?: optional given [mrb_bool] true if preceding argument (optional) is given.
*/
-mrb_int
+MRB_API mrb_int
mrb_get_args(mrb_state *mrb, const char *format, ...)
{
char c;
@@ -496,6 +535,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *p = *sp++;
+ i++;
+ break;
+ }
+ }
if (i < argc) {
*p = to_str(mrb, *sp++);
i++;
@@ -507,6 +554,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *p = *sp++;
+ i++;
+ break;
+ }
+ }
if (i < argc) {
*p = to_ary(mrb, *sp++);
i++;
@@ -518,6 +573,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p;
p = va_arg(ap, mrb_value*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *p = *sp++;
+ i++;
+ break;
+ }
+ }
if (i < argc) {
*p = to_hash(mrb, *sp++);
i++;
@@ -532,6 +595,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
ps = va_arg(ap, char**);
pl = va_arg(ap, mrb_int*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *ps = NULL;
+ *pl = 0;
+ i++;
+ break;
+ }
+ }
if (i < argc) {
ss = to_str(mrb, *sp++);
*ps = RSTRING_PTR(ss);
@@ -543,9 +615,17 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 'z':
{
mrb_value ss;
- char **ps;
-
- ps = va_arg(ap, char**);
+ const char **ps;
+
+ ps = va_arg(ap, const char**);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *ps = NULL;
+ i++; sp++;
+ break;
+ }
+ }
if (i < argc) {
ss = to_str(mrb, *sp++);
*ps = mrb_string_value_cstr(mrb, &ss);
@@ -562,6 +642,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pb = va_arg(ap, mrb_value**);
pl = va_arg(ap, mrb_int*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *pb = 0;
+ *pl = 0;
+ i++; sp++;
+ break;
+ }
+ }
if (i < argc) {
aa = to_ary(mrb, *sp++);
a = mrb_ary_ptr(aa);
@@ -635,16 +724,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value ss;
ss = *sp++;
- if (mrb_type(ss) == MRB_TT_SYMBOL) {
- *symp = mrb_symbol(ss);
- }
- else if (mrb_string_p(ss)) {
- *symp = mrb_intern_str(mrb, to_str(mrb, ss));
- }
- else {
- mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
- }
+ *symp = to_sym(mrb, ss);
i++;
}
}
@@ -656,6 +736,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
datap = va_arg(ap, void**);
type = va_arg(ap, struct mrb_data_type const*);
+ if (*format == '!') {
+ format++;
+ if (i < argc && mrb_nil_p(*sp)) {
+ *datap = 0;
+ i++; sp++;
+ break;
+ }
+ }
if (i < argc) {
*datap = mrb_data_get_ptr(mrb, *sp++, type);
++i;
@@ -739,47 +827,130 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
return c;
}
-void
-mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+static void
+boot_initmod(mrb_state *mrb, struct RClass *mod)
+{
+ mod->mt = kh_init(mt, mrb);
+}
+
+static struct RClass*
+include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super)
{
- struct RClass *ins_pos;
+ struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
+ if (m->tt == MRB_TT_ICLASS) {
+ m = m->c;
+ }
+ MRB_CLASS_ORIGIN(m);
+ ic->iv = m->iv;
+ ic->mt = m->mt;
+ ic->super = super;
+ if (m->tt == MRB_TT_ICLASS) {
+ ic->c = m->c;
+ } else {
+ ic->c = m;
+ }
+ return ic;
+}
+
+static int
+include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super)
+{
+ struct RClass *p, *ic;
+ void *klass_mt = find_origin(c)->mt;
- ins_pos = c;
while (m) {
- struct RClass *p = c, *ic;
int superclass_seen = 0;
- if (c->mt && c->mt == m->mt) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
- }
- while (p) {
- if (c != p && p->tt == MRB_TT_CLASS) {
- superclass_seen = 1;
- }
- else if (p->mt == m->mt) {
- if (p->tt == MRB_TT_ICLASS && !superclass_seen) {
- ins_pos = p;
+ if (m->flags & MRB_FLAG_IS_PREPENDED)
+ goto skip;
+
+ if (klass_mt && klass_mt == m->mt)
+ return -1;
+
+ p = c->super;
+ while(p) {
+ if (p->tt == MRB_TT_ICLASS) {
+ if (p->mt == m->mt) {
+ if (!superclass_seen) {
+ ins_pos = p; // move insert point
+ }
+ goto skip;
}
- goto skip;
+ } else if (p->tt == MRB_TT_CLASS) {
+ if (!search_super) break;
+ superclass_seen = 1;
}
p = p->super;
}
- ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class);
- if (m->tt == MRB_TT_ICLASS) {
- ic->c = m->c;
- }
- else {
- ic->c = m;
- }
- ic->mt = m->mt;
- ic->iv = m->iv;
- ic->super = ins_pos->super;
+
+ ic = include_class_new(mrb, m, ins_pos->super);
ins_pos->super = ic;
- mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic);
+ mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ins_pos->super);
ins_pos = ic;
skip:
m = m->super;
}
+ return 0;
+}
+
+MRB_API void
+mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+{
+ int changed = include_module_at(mrb, c, find_origin(c), m, 1);
+ if (changed < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
+ }
+}
+
+MRB_API void
+mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
+{
+ struct RClass *origin;
+ int changed = 0;
+
+ if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
+ origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
+ origin->flags |= MRB_FLAG_IS_ORIGIN;
+ origin->super = c->super;
+ c->super = origin;
+ origin->mt = c->mt;
+ c->mt = kh_init(mt, mrb);
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin);
+ c->flags |= MRB_FLAG_IS_PREPENDED;
+ }
+ changed = include_module_at(mrb, c, c, m, 0);
+ if (changed < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected");
+ }
+}
+
+static mrb_value
+mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value klass;
+
+ mrb_check_type(mrb, mod, MRB_TT_MODULE);
+ mrb_get_args(mrb, "C", &klass);
+ mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
+ return mod;
+}
+
+static mrb_value
+mrb_mod_prepend(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value *argv;
+ mrb_int argc, i;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ for (i=0; i<argc; i++) {
+ mrb_check_type(mrb, argv[i], MRB_TT_MODULE);
+ }
+ while (argc--) {
+ mrb_funcall(mrb, argv[argc], "prepend_features", 1, klass);
+ mrb_funcall(mrb, argv[argc], "prepended", 1, klass);
+ }
+
+ return klass;
}
static mrb_value
@@ -853,15 +1024,12 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
{
mrb_value result;
struct RClass *c = mrb_class_ptr(self);
-
result = mrb_ary_new(mrb);
- mrb_ary_push(mrb, result, mrb_obj_value(c));
- c = c->super;
while (c) {
if (c->tt == MRB_TT_ICLASS) {
mrb_ary_push(mrb, result, mrb_obj_value(c->c));
}
- else if (c->tt != MRB_TT_SCLASS) {
+ else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
mrb_ary_push(mrb, result, mrb_obj_value(c));
}
c = c->super;
@@ -886,11 +1054,15 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
{
mrb_value result;
struct RClass *c = mrb_class_ptr(self);
+ struct RClass *origin = c;
+ MRB_CLASS_ORIGIN(origin);
result = mrb_ary_new(mrb);
while (c) {
- if (c->tt == MRB_TT_ICLASS) {
- mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ if (c != origin && c->tt == MRB_TT_ICLASS) {
+ if (c->c->tt == MRB_TT_MODULE) {
+ mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+ }
}
c = c->super;
}
@@ -902,10 +1074,11 @@ static mrb_value
mrb_mod_initialize(mrb_state *mrb, mrb_value mod)
{
mrb_value b;
-
- mrb_get_args(mrb, "&", &b);
+ struct RClass *m = mrb_class_ptr(mod);
+ boot_initmod(mrb, m); // bootstrap a newly initialized module
+ mrb_get_args(mrb, "|&", &b);
if (!mrb_nil_p(b)) {
- mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod));
+ mrb_yield_with_class(mrb, b, 1, &mod, mod, m);
}
return mod;
}
@@ -958,7 +1131,7 @@ mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod)
return mod;
}
-mrb_value
+MRB_API mrb_value
mrb_singleton_class(mrb_state *mrb, mrb_value v)
{
struct RBasic *obj;
@@ -989,27 +1162,27 @@ mrb_singleton_class(mrb_state *mrb, mrb_value v)
return mrb_obj_value(obj->c);
}
-void
+MRB_API void
mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, mrb_aspec aspec)
{
prepare_singleton_class(mrb, (struct RBasic*)o);
mrb_define_method_id(mrb, o->c, mrb_intern_cstr(mrb, name), func, aspec);
}
-void
+MRB_API void
mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
{
mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec);
}
-void
+MRB_API void
mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
{
mrb_define_class_method(mrb, c, name, func, aspec);
mrb_define_method(mrb, c, name, func, aspec);
}
-struct RProc*
+MRB_API struct RProc*
mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
{
khiter_t k;
@@ -1030,10 +1203,10 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
}
c = c->super;
}
- return 0; /* no method */
+ return NULL; /* no method */
}
-struct RProc*
+MRB_API struct RProc*
mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
{
struct RProc *m;
@@ -1041,7 +1214,7 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0);
- if (RSTRING_LEN(inspect) > 64) {
+ if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) {
inspect = mrb_any_to_s(mrb, mrb_obj_value(c));
}
mrb_name_error(mrb, mid, "undefined method '%S' for class %S",
@@ -1051,6 +1224,91 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
}
static mrb_value
+attr_reader(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+}
+
+static mrb_value
+mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_value *argv;
+ mrb_int argc, i;
+ int ai;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ ai = mrb_gc_arena_save(mrb);
+ for (i=0; i<argc; i++) {
+ mrb_value name, str;
+ mrb_sym method, sym;
+
+ method = to_sym(mrb, argv[i]);
+ name = mrb_sym2str(mrb, method);
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
+ mrb_str_cat_lit(mrb, str, "@");
+ mrb_str_cat_str(mrb, str, name);
+ sym = mrb_intern_str(mrb, str);
+ mrb_iv_check(mrb, sym);
+ name = mrb_symbol_value(sym);
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
+attr_writer(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ mrb_value val;
+
+ mrb_get_args(mrb, "o", &val);
+ mrb_iv_set(mrb, obj, to_sym(mrb, name), val);
+ return val;
+}
+
+static mrb_value
+mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_value *argv;
+ mrb_int argc, i;
+ int ai;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ ai = mrb_gc_arena_save(mrb);
+ for (i=0; i<argc; i++) {
+ mrb_value name, str, attr;
+ mrb_sym method, sym;
+
+ method = to_sym(mrb, argv[i]);
+
+ /* prepare iv name (@name) */
+ name = mrb_sym2str(mrb, method);
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
+ mrb_str_cat_lit(mrb, str, "@");
+ mrb_str_cat_str(mrb, str, name);
+ sym = mrb_intern_str(mrb, str);
+ mrb_iv_check(mrb, sym);
+ attr = mrb_symbol_value(sym);
+
+ /* prepare method name (name=) */
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(str));
+ mrb_str_cat_str(mrb, str, name);
+ mrb_str_cat_lit(mrb, str, "=");
+ method = mrb_intern_str(mrb, str);
+
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
{
struct RClass *c = mrb_class_ptr(cv);
@@ -1069,15 +1327,15 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
* call-seq:
* class.new(args, ...) -> obj
*
- * Calls <code>allocate</code> to create a new object of
- * <i>class</i>'s class, then invokes that object's
- * <code>initialize</code> method, passing it <i>args</i>.
- * This is the method that ends up getting called whenever
- * an object is constructed using .new.
+ * Creates a new object of <i>class</i>'s class, then
+ * invokes that object's <code>initialize</code> method,
+ * passing it <i>args</i>. This is the method that ends
+ * up getting called whenever an object is constructed using
+ * `.new`.
*
*/
-mrb_value
+MRB_API mrb_value
mrb_instance_new(mrb_state *mrb, mrb_value cv)
{
mrb_value obj, blk;
@@ -1091,7 +1349,7 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv)
return obj;
}
-mrb_value
+MRB_API mrb_value
mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
{
mrb_value obj;
@@ -1137,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass)
struct RClass *c;
c = mrb_class_ptr(klass);
- c = c->super;
+ c = find_origin(c)->super;
while (c && c->tt == MRB_TT_ICLASS) {
- c = c->super;
+ c = find_origin(c)->super;
}
if (!c) return mrb_nil_value();
return mrb_obj_value(c);
@@ -1157,6 +1415,31 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv)
return mrb_bool_value(!mrb_test(cv));
}
+void
+mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
+{
+ mrb_sym inspect;
+ mrb_value repr;
+
+ inspect = mrb_intern_lit(mrb, "inspect");
+ if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
+ /* method missing in inspect; avoid recursion */
+ repr = mrb_any_to_s(mrb, self);
+ }
+ else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
+ repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
+ if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
+ repr = mrb_any_to_s(mrb, self);
+ }
+ }
+ else {
+ repr = mrb_any_to_s(mrb, self);
+ }
+
+ mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
+ mrb_sym2str(mrb, name), repr);
+}
+
/* 15.3.1.3.30 */
/*
* call-seq:
@@ -1196,32 +1479,14 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
mrb_sym name;
mrb_value *a;
mrb_int alen;
- mrb_sym inspect;
- mrb_value repr;
mrb_get_args(mrb, "n*", &name, &a, &alen);
-
- inspect = mrb_intern_lit(mrb, "inspect");
- if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
- /* method missing in inspect; avoid recursion */
- repr = mrb_any_to_s(mrb, mod);
- }
- else if (mrb_respond_to(mrb, mod, inspect)) {
- repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0);
- if (RSTRING_LEN(repr) > 64) {
- repr = mrb_any_to_s(mrb, mod);
- }
- }
- else {
- repr = mrb_any_to_s(mrb, mod);
- }
-
- mrb_no_method_error(mrb, name, alen, a, "undefined method '%S' for %S", mrb_sym2str(mrb, name), repr);
+ mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
/* not reached */
return mrb_nil_value();
}
-mrb_bool
+MRB_API mrb_bool
mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
{
khiter_t k;
@@ -1245,13 +1510,13 @@ mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
return FALSE; /* no method */
}
-mrb_bool
+MRB_API mrb_bool
mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid)
{
return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid);
}
-mrb_value
+MRB_API mrb_value
mrb_class_path(mrb_state *mrb, struct RClass *c)
{
mrb_value path;
@@ -1291,18 +1556,18 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
return path;
}
-struct RClass *
+MRB_API struct RClass *
mrb_class_real(struct RClass* cl)
{
if (cl == 0)
- return 0;
+ return NULL;
while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) {
cl = cl->super;
}
return cl;
}
-const char*
+MRB_API const char*
mrb_class_name(mrb_state *mrb, struct RClass* c)
{
mrb_value path = mrb_class_path(mrb, c);
@@ -1314,7 +1579,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c)
return RSTRING_PTR(path);
}
-const char*
+MRB_API const char*
mrb_obj_classname(mrb_state *mrb, mrb_value obj)
{
return mrb_class_name(mrb, mrb_obj_class(mrb, obj));
@@ -1346,7 +1611,7 @@ mrb_check_inheritable(mrb_state *mrb, struct RClass *super)
* \exception TypeError \a super is not inheritable.
* \exception TypeError \a super is the Class class.
*/
-struct RClass *
+MRB_API struct RClass*
mrb_class_new(mrb_state *mrb, struct RClass *super)
{
struct RClass *c;
@@ -1366,12 +1631,11 @@ mrb_class_new(mrb_state *mrb, struct RClass *super)
/*!
* Creates a new module.
*/
-struct RClass *
+MRB_API struct RClass*
mrb_module_new(mrb_state *mrb)
{
struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class);
- m->mt = kh_init(mt, mrb);
-
+ boot_initmod(mrb, m);
return m;
}
@@ -1389,18 +1653,18 @@ mrb_module_new(mrb_state *mrb)
* self.class #=> Object
*/
-struct RClass*
+MRB_API struct RClass*
mrb_obj_class(mrb_state *mrb, mrb_value obj)
{
- return mrb_class_real(mrb_class(mrb, obj));
+ return mrb_class_real(mrb_class(mrb, obj));
}
-void
+MRB_API void
mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
{
struct RProc *m = mrb_method_search(mrb, c, b);
- mrb_define_method_vm(mrb, c, a, mrb_obj_value(m));
+ mrb_define_method_raw(mrb, c, a, m);
}
/*!
@@ -1409,7 +1673,7 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
* \param name1 a new name for the method
* \param name2 the original name of the method
*/
-void
+MRB_API void
mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2)
{
mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2));
@@ -1438,13 +1702,13 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
case MRB_TT_CLASS:
case MRB_TT_MODULE:
case MRB_TT_SCLASS:
- mrb_str_append(mrb, str, mrb_inspect(mrb, v));
+ mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v));
break;
default:
- mrb_str_append(mrb, str, mrb_any_to_s(mrb, v));
+ mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v));
break;
}
- mrb_str_cat_lit(mrb, str, ">");
+ return mrb_str_cat_lit(mrb, str, ">");
}
else {
struct RClass *c;
@@ -1470,14 +1734,12 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
break;
}
mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
- mrb_str_cat_lit(mrb, str, ">");
+ return mrb_str_cat_lit(mrb, str, ">");
}
else {
- str = path;
+ return path;
}
}
-
- return str;
}
static mrb_value
@@ -1494,24 +1756,21 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod)
static void
undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
{
- mrb_value m;
-
if (!mrb_obj_respond_to(mrb, c, a)) {
mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c));
}
else {
- MRB_SET_VALUE(m, MRB_TT_PROC, value.p, 0);
- mrb_define_method_vm(mrb, c, a, m);
+ mrb_define_method_raw(mrb, c, a, NULL);
}
}
-void
+MRB_API void
mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
{
undef_method(mrb, c, mrb_intern_cstr(mrb, name));
}
-void
+MRB_API void
mrb_undef_class_method(mrb_state *mrb, struct RClass *c, const char *name)
{
mrb_undef_method(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name);
@@ -1552,43 +1811,20 @@ mod_define_method(mrb_state *mrb, mrb_value self)
}
static void
-check_cv_name_sym(mrb_state *mrb, mrb_sym id)
-{
- const char *s;
- mrb_int len;
-
- s = mrb_sym2name_len(mrb, id, &len);
- if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
- mrb_name_error(mrb, id, "`%S' is not allowed as a class variable name", mrb_sym2str(mrb, id));
- }
-}
-
-static void
check_cv_name_str(mrb_state *mrb, mrb_value str)
{
const char *s = RSTRING_PTR(str);
mrb_int len = RSTRING_LEN(str);
if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
- mrb_name_error(mrb, mrb_intern_str(mrb, str), "`%S' is not allowed as a class variable name", str);
+ mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str);
}
}
-static mrb_value
-get_sym_or_str_arg(mrb_state *mrb)
+static void
+check_cv_name_sym(mrb_state *mrb, mrb_sym id)
{
- mrb_value sym_or_str;
-
- mrb_get_args(mrb, "o", &sym_or_str);
-
- if (mrb_symbol_p(sym_or_str) || mrb_string_p(sym_or_str)) {
- return sym_or_str;
- }
- else {
- mrb_value obj = mrb_funcall(mrb, sym_or_str, "inspect", 0);
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
- return mrb_nil_value();
- }
+ check_cv_name_str(mrb, mrb_sym2str(mrb, id));
}
/* 15.2.2.4.16 */
@@ -1609,26 +1845,11 @@ get_sym_or_str_arg(mrb_state *mrb)
static mrb_value
mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
{
- mrb_value id;
- mrb_bool defined_p;
+ mrb_sym id;
- id = get_sym_or_str_arg(mrb);
- if (mrb_symbol_p(id)) {
- check_cv_name_sym(mrb, mrb_symbol(id));
- defined_p = mrb_cv_defined(mrb, mod, mrb_symbol(id));
- }
- else {
- mrb_value sym;
- check_cv_name_str(mrb, id);
- sym = mrb_check_intern_str(mrb, id);
- if (mrb_nil_p(sym)) {
- defined_p = FALSE;
- }
- else {
- defined_p = mrb_cv_defined(mrb, mod, mrb_symbol(sym));
- }
- }
- return mrb_bool_value(defined_p);
+ mrb_get_args(mrb, "n", &id);
+ check_cv_name_sym(mrb, id);
+ return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
}
/* 15.2.2.4.17 */
@@ -1763,41 +1984,29 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
static mrb_value
mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
{
- mrb_value id;
- mrb_bool method_defined_p;
+ mrb_sym id;
- id = get_sym_or_str_arg(mrb);
- if (mrb_symbol_p(id)) {
- method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(id));
- }
- else {
- mrb_value sym = mrb_check_intern_str(mrb, id);
- if (mrb_nil_p(sym)) {
- method_defined_p = FALSE;
- }
- else {
- method_defined_p = mrb_obj_respond_to(mrb, mrb_class_ptr(mod), mrb_symbol(sym));
- }
- }
- return mrb_bool_value(method_defined_p);
+ mrb_get_args(mrb, "n", &id);
+ return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id));
}
static void
remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
{
struct RClass *c = mrb_class_ptr(mod);
- khash_t(mt) *h = c->mt;
+ khash_t(mt) *h = find_origin(c)->mt;
khiter_t k;
if (h) {
k = kh_get(mt, mrb, h, mid);
if (k != kh_end(h)) {
kh_del(mt, mrb, h, k);
+ mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid));
return;
}
}
- mrb_name_error(mrb, mid, "method `%S' not defined in %S",
+ mrb_name_error(mrb, mid, "method '%S' not defined in %S",
mrb_sym2str(mrb, mid), mod);
}
@@ -1824,17 +2033,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
return mod;
}
-static void
-check_const_name_sym(mrb_state *mrb, mrb_sym id)
-{
- const char *s;
- mrb_int len;
- s = mrb_sym2name_len(mrb, id, &len);
- if (len < 1 || !ISUPPER(*s)) {
- mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id));
- }
-}
static void
check_const_name_str(mrb_state *mrb, mrb_value str)
@@ -1844,30 +2043,30 @@ check_const_name_str(mrb_state *mrb, mrb_value str)
}
}
-static mrb_value
-mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
+static void
+check_const_name_sym(mrb_state *mrb, mrb_sym id)
{
- mrb_value id;
- mrb_bool const_defined_p;
+ check_const_name_str(mrb, mrb_sym2str(mrb, id));
+}
- id = get_sym_or_str_arg(mrb);
- if (mrb_type(id) == MRB_TT_SYMBOL) {
- check_const_name_sym(mrb, mrb_symbol(id));
- const_defined_p = mrb_const_defined(mrb, mod, mrb_symbol(id));
- }
- else {
- mrb_value sym;
- check_const_name_str(mrb, id);
- sym = mrb_check_intern_str(mrb, id);
- if (mrb_nil_p(sym)) {
- const_defined_p = FALSE;
- }
- else {
- const_defined_p = mrb_const_defined(mrb, mod, mrb_symbol(sym));
- }
+static mrb_value
+const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit)
+{
+ if (inherit) {
+ return mrb_bool_value(mrb_const_defined(mrb, mod, id));
}
+ return mrb_bool_value(mrb_const_defined_at(mrb, mod, id));
+}
- return mrb_bool_value(const_defined_p);
+static mrb_value
+mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
+{
+ mrb_sym id;
+ mrb_bool inherit = TRUE;
+
+ mrb_get_args(mrb, "n|b", &id, &inherit);
+ check_const_name_sym(mrb, id);
+ return const_defined(mrb, mod, id, inherit);
}
static mrb_value
@@ -1946,6 +2145,43 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
return mrb_bool_value(eqq);
}
+MRB_API mrb_value
+mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value *argv;
+ mrb_int argc, i;
+ mrb_sym mid;
+ struct RProc *method_rproc;
+ struct RClass *rclass;
+ int ai;
+
+ mrb_check_type(mrb, mod, MRB_TT_MODULE);
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ if(argc == 0) {
+ /* set MODFUNC SCOPE if implemented */
+ return mod;
+ }
+
+ /* set PRIVATE method visibility if implemented */
+ /* mrb_mod_dummy_visibility(mrb, mod); */
+
+ for (i=0; i<argc; i++) {
+ mrb_check_type(mrb, argv[i], MRB_TT_SYMBOL);
+
+ mid = mrb_symbol(argv[i]);
+ rclass = mrb_class_ptr(mod);
+ method_rproc = mrb_method_search(mrb, rclass, mid);
+
+ prepare_singleton_class(mrb, (struct RBasic*)rclass);
+ ai = mrb_gc_arena_save(mrb);
+ mrb_define_method_raw(mrb, rclass->c, mid, method_rproc);
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return mod;
+}
+
void
mrb_init_class(mrb_state *mrb)
{
@@ -1979,6 +2215,9 @@ mrb_init_class(mrb_state *mrb)
name_class(mrb, mod, mrb_intern_lit(mrb, "Module")); /* 15.2.2 */
name_class(mrb, cls, mrb_intern_lit(mrb, "Class")); /* 15.2.3 */
+ mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class); /* 15.2.17 */
+ MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC);
+
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
@@ -1996,6 +2235,9 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
+ mrb_define_method(mrb, mod, "prepend", mrb_mod_prepend, MRB_ARGS_ANY());
+ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "include", mrb_mod_include, MRB_ARGS_ANY()); /* 15.2.2.4.27 */
mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */
mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */
@@ -2006,17 +2248,21 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */
mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */
mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */
+ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY());
mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */
mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */
mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */
mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
+ mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */
+ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */
mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, MRB_ARGS_ANY()); /* 15.2.2.4.8 */
mrb_define_method(mrb, mod, "ancestors", mrb_mod_ancestors, MRB_ARGS_NONE()); /* 15.2.2.4.9 */
mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
- mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.20 */
+ mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */
mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */
mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */
mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
diff --git a/src/codedump.c b/src/codedump.c
new file mode 100644
index 000000000..4f4b6de57
--- /dev/null
+++ b/src/codedump.c
@@ -0,0 +1,453 @@
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
+#include <mruby/opcode.h>
+#include <mruby/string.h>
+#include <mruby/proc.h>
+
+#ifndef MRB_DISABLE_STDIO
+static int
+print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
+{
+ size_t i;
+
+ if (n == 0) return 0;
+
+ for (i=0; i+1<irep->nlocals; i++) {
+ if (irep->lv[i].r == n) {
+ mrb_sym sym = irep->lv[i].name;
+ if (pre) printf(" ");
+ printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define RA 1
+#define RB 2
+#define RAB 3
+
+static void
+print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r)
+{
+ int pre = 0;
+
+ if (!irep->lv
+ || ((!(r & RA) || GETARG_A(c) >= irep->nlocals)
+ && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) {
+ printf("\n");
+ return;
+ }
+ printf("\t; ");
+ if (r & RA) {
+ pre = print_r(mrb, irep, GETARG_A(c), 0);
+ }
+ if (r & RB) {
+ print_r(mrb, irep, GETARG_B(c), pre);
+ }
+ printf("\n");
+}
+#endif
+
+static void
+codedump(mrb_state *mrb, mrb_irep *irep)
+{
+#ifndef MRB_DISABLE_STDIO
+ int i;
+ int ai;
+ mrb_code c;
+ const char *file = NULL, *next_file;
+ int32_t line;
+
+ if (!irep) return;
+ printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep,
+ irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
+
+ for (i = 0; i < (int)irep->ilen; i++) {
+ ai = mrb_gc_arena_save(mrb);
+
+ next_file = mrb_debug_get_filename(irep, i);
+ if (next_file && file != next_file) {
+ printf("file: %s\n", next_file);
+ file = next_file;
+ }
+ line = mrb_debug_get_line(irep, i);
+ if (line < 0) {
+ printf(" ");
+ }
+ else {
+ printf("%5d ", line);
+ }
+
+ printf("%03d ", i);
+ c = irep->iseq[i];
+ switch (GET_OPCODE(c)) {
+ case OP_NOP:
+ printf("OP_NOP\n");
+ break;
+ case OP_MOVE:
+ printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_LOADL:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_inspect(mrb, v);
+ printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADI:
+ printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADSYM:
+ printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADNIL:
+ printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADSELF:
+ printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADT:
+ printf("OP_LOADT\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_LOADF:
+ printf("OP_LOADF\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETGLOBAL:
+ printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETGLOBAL:
+ printf("OP_SETGLOBAL\t:%s\tR%d\t",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETCONST:
+ printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETCONST:
+ printf("OP_SETCONST\t:%s\tR%d\t",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETMCNST:
+ printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_SETMCNST:
+ printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1,
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETIV:
+ printf("OP_GETIV\tR%d\t%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETIV:
+ printf("OP_SETIV\t%s\tR%d",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETUPVAR:
+ printf("OP_GETUPVAR\tR%d\t%d\t%d",
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETUPVAR:
+ printf("OP_SETUPVAR\tR%d\t%d\t%d",
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_GETCV:
+ printf("OP_GETCV\tR%d\t%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SETCV:
+ printf("OP_SETCV\t%s\tR%d",
+ mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
+ GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_JMP:
+ printf("OP_JMP\t%03d\n", i+GETARG_sBx(c));
+ break;
+ case OP_JMPIF:
+ printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
+ break;
+ case OP_JMPNOT:
+ printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
+ break;
+ case OP_SEND:
+ printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SENDB:
+ printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_TAILCALL:
+ printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUPER:
+ printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c),
+ GETARG_C(c));
+ break;
+ case OP_ARGARY:
+ printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c),
+ (GETARG_Bx(c)>>10)&0x3f,
+ (GETARG_Bx(c)>>9)&0x1,
+ (GETARG_Bx(c)>>4)&0x1f,
+ (GETARG_Bx(c)>>0)&0xf);
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_ENTER:
+ printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
+ (GETARG_Ax(c)>>18)&0x1f,
+ (GETARG_Ax(c)>>13)&0x1f,
+ (GETARG_Ax(c)>>12)&0x1,
+ (GETARG_Ax(c)>>7)&0x1f,
+ (GETARG_Ax(c)>>2)&0x1f,
+ (GETARG_Ax(c)>>1)&0x1,
+ GETARG_Ax(c) & 0x1);
+ break;
+ case OP_RETURN:
+ printf("OP_RETURN\tR%d", GETARG_A(c));
+ switch (GETARG_B(c)) {
+ case OP_R_NORMAL:
+ case OP_R_RETURN:
+ printf("\treturn\t"); break;
+ case OP_R_BREAK:
+ printf("\tbreak\t"); break;
+ default:
+ printf("\tbroken\t"); break;
+ break;
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_BLKPUSH:
+ printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c),
+ (GETARG_Bx(c)>>10)&0x3f,
+ (GETARG_Bx(c)>>9)&0x1,
+ (GETARG_Bx(c)>>4)&0x1f,
+ (GETARG_Bx(c)>>0)&0xf);
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_LAMBDA:
+ printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_RANGE:
+ printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_METHOD:
+ printf("OP_METHOD\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+
+ case OP_ADD:
+ printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_ADDI:
+ printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUB:
+ printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_SUBI:
+ printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_MUL:
+ printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_DIV:
+ printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_LT:
+ printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_LE:
+ printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_GT:
+ printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_GE:
+ printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+ case OP_EQ:
+ printf("OP_EQ\tR%d\t:%s\t%d\n", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
+ GETARG_C(c));
+ break;
+
+ case OP_STOP:
+ printf("OP_STOP\n");
+ break;
+
+ case OP_ARRAY:
+ printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_ARYCAT:
+ printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_ARYPUSH:
+ printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_AREF:
+ printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_APOST:
+ printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_STRING:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+ printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ }
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_STRCAT:
+ printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_HASH:
+ printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+
+ case OP_OCLASS:
+ printf("OP_OCLASS\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_CLASS:
+ printf("OP_CLASS\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_MODULE:
+ printf("OP_MODULE\tR%d\t:%s", GETARG_A(c),
+ mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_EXEC:
+ printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1);
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_SCLASS:
+ printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
+ print_lv(mrb, irep, c, RAB);
+ break;
+ case OP_TCLASS:
+ printf("OP_TCLASS\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_ERR:
+ {
+ mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+ printf("OP_ERR\t%s\n", RSTRING_PTR(s));
+ }
+ break;
+ case OP_EPUSH:
+ printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
+ break;
+ case OP_ONERR:
+ printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
+ break;
+ case OP_RESCUE:
+ printf("OP_RESCUE\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_RAISE:
+ printf("OP_RAISE\tR%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_POPERR:
+ printf("OP_POPERR\t%d\t\t", GETARG_A(c));
+ print_lv(mrb, irep, c, RA);
+ break;
+ case OP_EPOP:
+ printf("OP_EPOP\t%d\n", GETARG_A(c));
+ break;
+
+ default:
+ printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c),
+ GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ break;
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ printf("\n");
+#endif
+}
+
+static void
+codedump_recur(mrb_state *mrb, mrb_irep *irep)
+{
+ size_t i;
+
+ codedump(mrb, irep);
+ for (i=0; i<irep->rlen; i++) {
+ codedump_recur(mrb, irep->reps[i]);
+ }
+}
+
+void
+mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
+{
+ codedump_recur(mrb, proc->body.irep);
+}
diff --git a/src/codegen.c b/src/codegen.c
deleted file mode 100644
index 03c752826..000000000
--- a/src/codegen.c
+++ /dev/null
@@ -1,3129 +0,0 @@
-/*
-** codegen.c - mruby code generator
-**
-** See Copyright Notice in mruby.h
-*/
-
-#include <ctype.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include "mruby.h"
-#include "mruby/compile.h"
-#include "mruby/proc.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
-#include "mruby/debug.h"
-#include "node.h"
-#include "mruby/opcode.h"
-#include "mruby/re.h"
-#include "mrb_throw.h"
-
-typedef mrb_ast_node node;
-typedef struct mrb_parser_state parser_state;
-
-enum looptype {
- LOOP_NORMAL,
- LOOP_BLOCK,
- LOOP_FOR,
- LOOP_BEGIN,
- LOOP_RESCUE,
-};
-
-struct loopinfo {
- enum looptype type;
- int pc1, pc2, pc3, acc;
- int ensure_level;
- struct loopinfo *prev;
-};
-
-typedef struct scope {
- mrb_state *mrb;
- mrb_pool *mpool;
- struct mrb_jmpbuf jmp;
-
- struct scope *prev;
-
- node *lv;
-
- int sp;
- int pc;
- int lastlabel;
- int ainfo:15;
- mrb_bool mscope:1;
-
- struct loopinfo *loop;
- int ensure_level;
- char const *filename;
- uint16_t lineno;
-
- mrb_code *iseq;
- uint16_t *lines;
- int icapa;
-
- mrb_irep *irep;
- size_t pcapa;
- size_t scapa;
- size_t rcapa;
-
- uint16_t nlocals;
- uint16_t nregs;
- int ai;
-
- int debug_start_pos;
- uint16_t filename_index;
- parser_state* parser;
-} codegen_scope;
-
-static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
-static void scope_finish(codegen_scope *s);
-static struct loopinfo *loop_push(codegen_scope *s, enum looptype t);
-static void loop_break(codegen_scope *s, node *tree);
-static void loop_pop(codegen_scope *s, int val);
-
-static void gen_assignment(codegen_scope *s, node *node, int sp, int val);
-static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val);
-
-static void codegen(codegen_scope *s, node *tree, int val);
-
-static void
-codegen_error(codegen_scope *s, const char *message)
-{
- if (!s) return;
- while (s->prev) {
- codegen_scope *tmp = s->prev;
- mrb_pool_close(s->mpool);
- s = tmp;
- }
-#ifdef ENABLE_STDIO
- if (s->filename && s->lineno) {
- fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
- }
- else {
- fprintf(stderr, "codegen error: %s\n", message);
- }
-#endif
- MRB_THROW(&s->jmp);
-}
-
-static void*
-codegen_palloc(codegen_scope *s, size_t len)
-{
- void *p = mrb_pool_alloc(s->mpool, len);
-
- if (!p) codegen_error(s, "pool memory allocation");
- return p;
-}
-
-static void*
-codegen_malloc(codegen_scope *s, size_t len)
-{
- void *p = mrb_malloc_simple(s->mrb, len);
-
- if (!p) codegen_error(s, "mrb_malloc");
- return p;
-}
-
-static void*
-codegen_realloc(codegen_scope *s, void *p, size_t len)
-{
- p = mrb_realloc_simple(s->mrb, p, len);
-
- if (!p && len > 0) codegen_error(s, "mrb_realloc");
- return p;
-}
-
-static int
-new_label(codegen_scope *s)
-{
- s->lastlabel = s->pc;
- return s->pc;
-}
-
-static inline int
-genop(codegen_scope *s, mrb_code i)
-{
- if (s->pc == s->icapa) {
- s->icapa *= 2;
- s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
- if (s->lines) {
- s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
- s->irep->lines = s->lines;
- }
- }
- s->iseq[s->pc] = i;
- if (s->lines) {
- s->lines[s->pc] = s->lineno;
- }
- return s->pc++;
-}
-
-#define NOVAL 0
-#define VAL 1
-
-static int
-genop_peep(codegen_scope *s, mrb_code i, int val)
-{
- /* peephole optimization */
- if (s->lastlabel != s->pc && s->pc > 0) {
- mrb_code i0 = s->iseq[s->pc-1];
- int c1 = GET_OPCODE(i);
- int c0 = GET_OPCODE(i0);
-
- switch (c1) {
- case OP_MOVE:
- if (GETARG_A(i) == GETARG_B(i)) {
- /* skip useless OP_MOVE */
- return 0;
- }
- if (val) break;
- switch (c0) {
- case OP_MOVE:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0) && GETARG_A(i) >= s->nlocals) {
- /* skip swapping OP_MOVE */
- return 0;
- }
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0));
- return 0;
- }
- break;
- case OP_LOADI:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
- return 0;
- }
- break;
- case OP_ARRAY:
- case OP_HASH:
- case OP_RANGE:
- case OP_AREF:
- case OP_GETUPVAR:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
- return 0;
- }
- break;
- case OP_LOADSYM:
- case OP_GETGLOBAL:
- case OP_GETIV:
- case OP_GETCV:
- case OP_GETCONST:
- case OP_GETSPECIAL:
- case OP_LOADL:
- case OP_STRING:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
- return 0;
- }
- break;
- case OP_SCLASS:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
- return 0;
- }
- break;
- case OP_LOADNIL:
- case OP_LOADSELF:
- case OP_LOADT:
- case OP_LOADF:
- case OP_OCLASS:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
- return 0;
- }
- break;
- default:
- break;
- }
- break;
- case OP_SETIV:
- case OP_SETCV:
- case OP_SETCONST:
- case OP_SETMCNST:
- case OP_SETGLOBAL:
- if (val) break;
- if (c0 == OP_MOVE) {
- if (GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
- return 0;
- }
- }
- break;
- case OP_SETUPVAR:
- if (val) break;
- if (c0 == OP_MOVE) {
- if (GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
- return 0;
- }
- }
- break;
- case OP_EPOP:
- if (c0 == OP_EPOP) {
- s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
- return 0;
- }
- break;
- case OP_POPERR:
- if (c0 == OP_POPERR) {
- s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
- return 0;
- }
- break;
- case OP_RETURN:
- switch (c0) {
- case OP_RETURN:
- return 0;
- case OP_MOVE:
- if (GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
- return 0;
- }
- break;
- case OP_SETIV:
- case OP_SETCV:
- case OP_SETCONST:
- case OP_SETMCNST:
- case OP_SETUPVAR:
- case OP_SETGLOBAL:
- s->pc--;
- genop_peep(s, i0, NOVAL);
- i0 = s->iseq[s->pc-1];
- return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
-#if 0
- case OP_SEND:
- if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0));
- return;
- }
- break;
-#endif
- default:
- break;
- }
- break;
- case OP_ADD:
- case OP_SUB:
- if (c0 == OP_LOADI) {
- int c = GETARG_sBx(i0);
-
- if (c1 == OP_SUB) c = -c;
- if (c > 127 || c < -127) break;
- if (0 <= c)
- s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
- else
- s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
- return 0;
- }
- case OP_STRCAT:
- if (c0 == OP_STRING) {
- int i = GETARG_Bx(i0);
-
- if (mrb_type(s->irep->pool[i]) == MRB_TT_STRING &&
- RSTRING_LEN(s->irep->pool[i]) == 0) {
- s->pc--;
- return 0;
- }
- }
- break;
- case OP_JMPIF:
- case OP_JMPNOT:
- if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
- return s->pc-1;
- }
- break;
- default:
- break;
- }
- }
- return genop(s, i);
-}
-
-static void
-scope_error(codegen_scope *s)
-{
- exit(EXIT_FAILURE);
-}
-
-static inline void
-dispatch(codegen_scope *s, int pc)
-{
- int diff = s->pc - pc;
- mrb_code i = s->iseq[pc];
- int c = GET_OPCODE(i);
-
- s->lastlabel = s->pc;
- switch (c) {
- case OP_JMP:
- case OP_JMPIF:
- case OP_JMPNOT:
- case OP_ONERR:
- break;
- default:
-#ifdef ENABLE_STDIO
- fprintf(stderr, "bug: dispatch on non JMP op\n");
-#endif
- scope_error(s);
- break;
- }
- s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
-}
-
-static void
-dispatch_linked(codegen_scope *s, int pc)
-{
- mrb_code i;
- int pos;
-
- if (!pc) return;
- for (;;) {
- i = s->iseq[pc];
- pos = GETARG_sBx(i);
- dispatch(s, pc);
- if (!pos) break;
- pc = pos;
- }
-}
-
-#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
-static void
-push_(codegen_scope *s)
-{
- if (s->sp > 511) {
- codegen_error(s, "too complex expression");
- }
- s->sp++;
- nregs_update;
-}
-
-#define push() push_(s)
-#define pop_(s) ((s)->sp--)
-#define pop() pop_(s)
-#define pop_n(n) (s->sp-=(n))
-#define cursp() (s->sp)
-
-static inline int
-new_lit(codegen_scope *s, mrb_value val)
-{
- size_t i;
- mrb_value *pv;
-
- switch (mrb_type(val)) {
- case MRB_TT_STRING:
- for (i=0; i<s->irep->plen; i++) {
- mrb_int len;
- pv = &s->irep->pool[i];
-
- if (mrb_type(*pv) != MRB_TT_STRING) continue;
- if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
- if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
- return i;
- }
- break;
- case MRB_TT_FLOAT:
- for (i=0; i<s->irep->plen; i++) {
- pv = &s->irep->pool[i];
- if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
- if (mrb_float(*pv) == mrb_float(val)) return i;
- }
- break;
- case MRB_TT_FIXNUM:
- for (i=0; i<s->irep->plen; i++) {
- pv = &s->irep->pool[i];
- if (!mrb_fixnum_p(*pv)) continue;
- if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i;
- }
- break;
- default:
- /* should not happen */
- return 0;
- }
-
- if (s->irep->plen == s->pcapa) {
- s->pcapa *= 2;
- s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa);
- }
-
- pv = &s->irep->pool[s->irep->plen];
- i = s->irep->plen++;
-
- switch (mrb_type(val)) {
- case MRB_TT_STRING:
- *pv = mrb_str_pool(s->mrb, val);
- break;
-
- case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- *pv = mrb_float_pool(s->mrb, mrb_float(val));
- break;
-#endif
- case MRB_TT_FIXNUM:
- *pv = val;
- break;
-
- default:
- /* should not happen */
- break;
- }
- return i;
-}
-
-static inline int
-new_msym(codegen_scope *s, mrb_sym sym)
-{
- size_t i, len;
-
- mrb_assert(s->irep);
-
- len = s->irep->slen;
- if (len > 256) len = 256;
- for (i=0; i<len; i++) {
- if (s->irep->syms[i] == sym) return i;
- if (s->irep->syms[i] == 0) break;
- }
- if (i == 256) {
- codegen_error(s, "too many symbols (max 256)");
- }
- s->irep->syms[i] = sym;
- if (i == s->irep->slen) s->irep->slen++;
- return i;
-}
-
-static inline int
-new_sym(codegen_scope *s, mrb_sym sym)
-{
- size_t i;
-
- for (i=0; i<s->irep->slen; i++) {
- if (s->irep->syms[i] == sym) return i;
- }
- if (s->irep->slen > 125 && s->irep->slen < 256) {
- s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536);
- for (i = 0; i < 256 - s->irep->slen; i++) {
- static const mrb_sym mrb_sym_zero = { 0 };
- s->irep->syms[i + s->irep->slen] = mrb_sym_zero;
- }
- s->irep->slen = 256;
- }
- s->irep->syms[s->irep->slen] = sym;
- return s->irep->slen++;
-}
-
-static int
-node_len(node *tree)
-{
- int n = 0;
-
- while (tree) {
- n++;
- tree = tree->cdr;
- }
- return n;
-}
-
-#define sym(x) ((mrb_sym)(intptr_t)(x))
-#define lv_name(lv) sym((lv)->car)
-static int
-lv_idx(codegen_scope *s, mrb_sym id)
-{
- node *lv = s->lv;
- int n = 1;
-
- while (lv) {
- if (lv_name(lv) == id) return n;
- n++;
- lv = lv->cdr;
- }
- return 0;
-}
-
-static void
-for_body(codegen_scope *s, node *tree)
-{
- codegen_scope *prev = s;
- int idx;
- struct loopinfo *lp;
- node *n2;
- mrb_code c;
-
- /* generate receiver */
- codegen(s, tree->cdr->car, VAL);
- /* generate loop-block */
- s = scope_new(s->mrb, s, NULL);
- push(); /* push for a block parameter */
-
- lp = loop_push(s, LOOP_FOR);
- lp->pc1 = new_label(s);
-
- /* generate loop variable */
- n2 = tree->car;
- if (n2->car && !n2->car->cdr && !n2->cdr) {
- genop(s, MKOP_Ax(OP_ENTER, 0x40000));
- gen_assignment(s, n2->car->car, 1, NOVAL);
- }
- else {
- genop(s, MKOP_Ax(OP_ENTER, 0x40000));
- gen_vmassignment(s, n2, 1, VAL);
- }
- codegen(s, tree->cdr->cdr->car, VAL);
- pop();
- if (s->pc > 0) {
- c = s->iseq[s->pc-1];
- if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel)
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
- loop_pop(s, NOVAL);
- scope_finish(s);
- s = prev;
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
- pop();
- idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
- genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
-}
-
-static int
-lambda_body(codegen_scope *s, node *tree, int blk)
-{
- mrb_code c;
- codegen_scope *parent = s;
- s = scope_new(s->mrb, s, tree->car);
- s->mscope = !blk;
-
- if (blk) {
- struct loopinfo *lp = loop_push(s, LOOP_BLOCK);
- lp->pc1 = new_label(s);
- }
- tree = tree->cdr;
- if (tree->car) {
- mrb_aspec a;
- int ma, oa, ra, pa, ka, kd, ba;
- int pos, i;
- node *n, *opt;
-
- ma = node_len(tree->car->car);
- n = tree->car->car;
- while (n) {
- n = n->cdr;
- }
- oa = node_len(tree->car->cdr->car);
- ra = tree->car->cdr->cdr->car ? 1 : 0;
- pa = node_len(tree->car->cdr->cdr->cdr->car);
- ka = kd = 0;
- ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
-
- a = ((mrb_aspec)(ma & 0x1f) << 18)
- | ((mrb_aspec)(oa & 0x1f) << 13)
- | ((ra & 1) << 12)
- | ((pa & 0x1f) << 7)
- | ((ka & 0x1f) << 2)
- | ((kd & 1)<< 1)
- | (ba & 1);
- s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */
- | ((ra & 1) << 5)
- | (pa & 0x1f);
- genop(s, MKOP_Ax(OP_ENTER, a));
- pos = new_label(s);
- for (i=0; i<oa; i++) {
- new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
- }
- if (oa > 0) {
- genop(s, MKOP_sBx(OP_JMP, 0));
- }
- opt = tree->car->cdr->car;
- i = 0;
- while (opt) {
- int idx;
-
- dispatch(s, pos+i);
- codegen(s, opt->car->cdr, VAL);
- idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car);
- pop();
- genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL);
- i++;
- opt = opt->cdr;
- }
- if (oa > 0) {
- dispatch(s, pos+i);
- }
- }
- codegen(s, tree->cdr->car, VAL);
- pop();
- if (s->pc > 0) {
- c = s->iseq[s->pc-1];
- if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) {
- if (s->nregs == 0) {
- genop(s, MKOP_A(OP_LOADNIL, 0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
- }
- }
- if (blk) {
- loop_pop(s, NOVAL);
- }
- scope_finish(s);
- return parent->irep->rlen - 1;
-}
-
-static int
-scope_body(codegen_scope *s, node *tree, int val)
-{
- codegen_scope *scope = scope_new(s->mrb, s, tree->car);
-
- codegen(scope, tree->cdr, VAL);
- if (!s->iseq) {
- genop(scope, MKOP_A(OP_STOP, 0));
- }
- else if (!val) {
- genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- if (scope->nregs == 0) {
- genop(scope, MKOP_A(OP_LOADNIL, 0));
- genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL);
- }
- }
- scope_finish(scope);
- if (!s->irep) {
- /* should not happen */
- return 0;
- }
- return s->irep->rlen - 1;
-}
-
-static mrb_bool
-nosplat(node *t)
-{
- while (t) {
- if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE;
- t = t->cdr;
- }
- return TRUE;
-}
-
-static mrb_sym
-attrsym(codegen_scope *s, mrb_sym a)
-{
- const char *name;
- mrb_int len;
- char *name2;
-
- name = mrb_sym2name_len(s->mrb, a, &len);
- name2 = (char *)codegen_palloc(s,
- (size_t)len
- + 1 /* '=' */
- + 1 /* '\0' */
- );
- mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
- memcpy(name2, name, (size_t)len);
- name2[len] = '=';
- name2[len+1] = '\0';
-
- return mrb_intern(s->mrb, name2, len+1);
-}
-
-static int
-gen_values(codegen_scope *s, node *t, int val)
-{
- int n = 0;
- int is_splat;
-
- while (t) {
- is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
- if (n >= 127 || is_splat) {
- if (val) {
- pop_n(n);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
- push();
- codegen(s, t->car, VAL);
- pop(); pop();
- if (is_splat) {
- genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
- }
- else {
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
- }
- t = t->cdr;
- while (t) {
- push();
- codegen(s, t->car, VAL);
- pop(); pop();
- if ((intptr_t)t->car->car == NODE_SPLAT) {
- genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
- }
- else {
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
- }
- t = t->cdr;
- }
- }
- else {
- codegen(s, t->car->cdr, NOVAL);
- t = t->cdr;
- while (t) {
- codegen(s, t->car, NOVAL);
- t = t->cdr;
- }
- }
- return -1;
- }
- /* normal (no splat) mode */
- codegen(s, t->car, val);
- n++;
- t = t->cdr;
- }
- return n;
-}
-
-#define CALL_MAXARGS 127
-
-static void
-gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val)
-{
- mrb_sym sym = name ? name : sym(tree->cdr->car);
- int idx;
- int n = 0, noop = 0, sendv = 0, blk = 0;
-
- codegen(s, tree->car, VAL); /* receiver */
- idx = new_msym(s, sym);
- tree = tree->cdr->cdr->car;
- if (tree) {
- n = gen_values(s, tree->car, VAL);
- if (n < 0) {
- n = noop = sendv = 1;
- push();
- }
- }
- if (sp) {
- if (sendv) {
- pop();
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp));
- push();
- }
- else {
- genop(s, MKOP_AB(OP_MOVE, cursp(), sp));
- push();
- n++;
- }
- }
- if (tree && tree->cdr) {
- noop = 1;
- codegen(s, tree->cdr, VAL);
- pop();
- }
- else {
- blk = cursp();
- }
- push();pop();
- pop_n(n+1);
- {
- mrb_int len;
- const char *name = mrb_sym2name_len(s->mrb, sym, &len);
-
- if (!noop && len == 1 && name[0] == '+') {
- genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val);
- }
- else if (!noop && len == 1 && name[0] == '-') {
- genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val);
- }
- else if (!noop && len == 1 && name[0] == '*') {
- genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n));
- }
- else if (!noop && len == 1 && name[0] == '/') {
- genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n));
- }
- else if (!noop && len == 1 && name[0] == '<') {
- genop(s, MKOP_ABC(OP_LT, cursp(), idx, n));
- }
- else if (!noop && len == 2 && name[0] == '<' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_LE, cursp(), idx, n));
- }
- else if (!noop && len == 1 && name[0] == '>') {
- genop(s, MKOP_ABC(OP_GT, cursp(), idx, n));
- }
- else if (!noop && len == 2 && name[0] == '>' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_GE, cursp(), idx, n));
- }
- else if (!noop && len == 2 && name[0] == '=' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
- }
- else {
- if (sendv) n = CALL_MAXARGS;
- if (blk > 0) { /* no block */
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n));
- }
- else {
- genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n));
- }
- }
- }
- if (val) {
- push();
- }
-}
-
-static void
-gen_assignment(codegen_scope *s, node *node, int sp, int val)
-{
- int idx;
- int type = (intptr_t)node->car;
-
- node = node->cdr;
- switch ((intptr_t)type) {
- case NODE_GVAR:
- idx = new_sym(s, sym(node));
- genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
- break;
- case NODE_LVAR:
- idx = lv_idx(s, sym(node));
- if (idx > 0) {
- if (idx != sp) {
- genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val);
- }
- break;
- }
- else { /* upvar */
- int lv = 0;
- codegen_scope *up = s->prev;
-
- while (up) {
- idx = lv_idx(up, sym(node));
- if (idx > 0) {
- genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val);
- break;
- }
- lv++;
- up = up->prev;
- }
- }
- break;
- case NODE_IVAR:
- idx = new_sym(s, sym(node));
- genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val);
- break;
- case NODE_CVAR:
- idx = new_sym(s, sym(node));
- genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val);
- break;
- case NODE_CONST:
- idx = new_sym(s, sym(node));
- genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val);
- break;
- case NODE_COLON2:
- idx = new_sym(s, sym(node->cdr));
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL);
- push();
- codegen(s, node->car, VAL);
- pop_n(2);
- genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val);
- break;
-
- case NODE_CALL:
- push();
- gen_call(s, node, attrsym(s, sym(node->cdr->car)), sp, NOVAL);
- pop();
- if (val) {
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val);
- }
- break;
-
- default:
-#ifdef ENABLE_STDIO
- printf("unknown lhs %d\n", type);
-#endif
- break;
- }
- if (val) push();
-}
-
-static void
-gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
-{
- int n = 0, post = 0;
- node *t, *p;
-
- if (tree->car) { /* pre */
- t = tree->car;
- n = 0;
- while (t) {
- genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n));
- gen_assignment(s, t->car, cursp(), NOVAL);
- n++;
- t = t->cdr;
- }
- }
- t = tree->cdr;
- if (t) {
- if (t->cdr) { /* post count */
- p = t->cdr->car;
- while (p) {
- post++;
- p = p->cdr;
- }
- }
- if (val) {
- genop(s, MKOP_AB(OP_MOVE, cursp(), rhs));
- push();
- }
- pop();
- genop(s, MKOP_ABC(OP_APOST, cursp(), n, post));
- n = 1;
- if (t->car) { /* rest */
- gen_assignment(s, t->car, cursp(), NOVAL);
- }
- if (t->cdr && t->cdr->car) {
- t = t->cdr->car;
- while (t) {
- gen_assignment(s, t->car, cursp()+n, NOVAL);
- t = t->cdr;
- n++;
- }
- }
- }
- else {
- pop();
- }
-}
-
-static void
-gen_send_intern(codegen_scope *s)
-{
- pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
- push();
-}
-static void
-gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
-{
- if (val) {
- int i = 0, j = 0;
-
- while (tree) {
- switch ((intptr_t)tree->car->car) {
- case NODE_STR:
- if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0))
- break;
- /* fall through */
- case NODE_BEGIN:
- codegen(s, tree->car, VAL);
- ++j;
- break;
-
- case NODE_LITERAL_DELIM:
- if (j > 0) {
- j = 0;
- ++i;
- if (sym)
- gen_send_intern(s);
- }
- break;
- }
- if (j >= 2) {
- pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
- push();
- j = 1;
- }
- tree = tree->cdr;
- }
- if (j > 0) {
- ++i;
- if (sym)
- gen_send_intern(s);
- }
- pop_n(i);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i));
- push();
- }
- else {
- while (tree) {
- switch ((intptr_t)tree->car->car) {
- case NODE_BEGIN: case NODE_BLOCK:
- codegen(s, tree->car, NOVAL);
- }
- tree = tree->cdr;
- }
- }
-}
-
-static void
-raise_error(codegen_scope *s, const char *msg)
-{
- int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg));
-
- genop(s, MKOP_ABx(OP_ERR, 1, idx));
-}
-
-static double
-readint_float(codegen_scope *s, const char *p, int base)
-{
- const char *e = p + strlen(p);
- double f = 0;
- int n;
-
- if (*p == '+') p++;
- while (p < e) {
- char c = *p;
- c = tolower((unsigned char)c);
- for (n=0; n<base; n++) {
- if (mrb_digitmap[n] == c) {
- f *= base;
- f += n;
- break;
- }
- }
- if (n == base) {
- codegen_error(s, "malformed readint input");
- }
- p++;
- }
- return f;
-}
-
-static mrb_int
-readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow)
-{
- const char *e = p + strlen(p);
- mrb_int result = 0;
- int n;
-
- if (*p == '+') p++;
- while (p < e) {
- char c = *p;
- c = tolower((unsigned char)c);
- for (n=0; n<base; n++) {
- if (mrb_digitmap[n] == c) {
- break;
- }
- }
- if (n == base) {
- codegen_error(s, "malformed readint input");
- }
-
- if(base > 0) {
- if (neg) {
- if ((MRB_INT_MIN + n)/base > result) {
- *overflow = TRUE;
- return 0;
- }
- result *= base;
- result -= n;
- }
- else {
- if ((MRB_INT_MAX - n)/base < result) {
- *overflow = TRUE;
- return 0;
- }
- result *= base;
- result += n;
- }
- }
- p++;
- }
- *overflow = FALSE;
- return result;
-}
-
-static void
-codegen(codegen_scope *s, node *tree, int val)
-{
- int nt;
-
- if (!tree) return;
-
- if (s->irep && s->pc > 0 && s->filename_index != tree->filename_index) {
- s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
- mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
- s->debug_start_pos = s->pc;
- s->filename_index = tree->filename_index;
- s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
- }
-
- nt = (intptr_t)tree->car;
- s->lineno = tree->lineno;
- tree = tree->cdr;
- switch (nt) {
- case NODE_BEGIN:
- if (val && !tree) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- while (tree) {
- codegen(s, tree->car, tree->cdr ? NOVAL : val);
- tree = tree->cdr;
- }
- break;
-
- case NODE_RESCUE:
- {
- int onerr, noexc, exend, pos1, pos2, tmp;
- struct loopinfo *lp;
-
- onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
- lp = loop_push(s, LOOP_BEGIN);
- lp->pc1 = onerr;
- if (tree->car) {
- codegen(s, tree->car, val);
- if (val) pop();
- }
- lp->type = LOOP_RESCUE;
- noexc = genop(s, MKOP_Bx(OP_JMP, 0));
- dispatch(s, onerr);
- tree = tree->cdr;
- exend = 0;
- pos1 = 0;
- if (tree->car) {
- node *n2 = tree->car;
- int exc = cursp();
-
- genop(s, MKOP_A(OP_RESCUE, exc));
- push();
- while (n2) {
- node *n3 = n2->car;
- node *n4 = n3->car;
-
- if (pos1) dispatch(s, pos1);
- pos2 = 0;
- do {
- if (n4) {
- codegen(s, n4->car, VAL);
- }
- else {
- genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
- push();
- }
- genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
- pop();
- if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
- }
- else {
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
- }
- tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
- pos2 = tmp;
- if (n4) {
- n4 = n4->cdr;
- }
- } while (n4);
- pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch_linked(s, pos2);
-
- pop();
- if (n3->cdr->car) {
- gen_assignment(s, n3->cdr->car, exc, NOVAL);
- }
- if (n3->cdr->cdr->car) {
- codegen(s, n3->cdr->cdr->car, val);
- if (val) pop();
- }
- tmp = genop(s, MKOP_sBx(OP_JMP, exend));
- exend = tmp;
- n2 = n2->cdr;
- push();
- }
- if (pos1) {
- dispatch(s, pos1);
- genop(s, MKOP_A(OP_RAISE, exc));
- }
- }
- pop();
- tree = tree->cdr;
- dispatch(s, noexc);
- genop(s, MKOP_A(OP_POPERR, 1));
- if (tree->car) {
- codegen(s, tree->car, val);
- }
- else if (val) {
- push();
- }
- dispatch_linked(s, exend);
- loop_pop(s, NOVAL);
- }
- break;
-
- case NODE_ENSURE:
- {
- int idx;
- int epush = s->pc;
-
- genop(s, MKOP_Bx(OP_EPUSH, 0));
- s->ensure_level++;
- codegen(s, tree->car, val);
- idx = scope_body(s, tree->cdr, NOVAL);
- s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx);
- s->ensure_level--;
- genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
- }
- break;
-
- case NODE_LAMBDA:
- {
- int idx = lambda_body(s, tree, 1);
-
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA));
- push();
- }
- break;
-
- case NODE_BLOCK:
- {
- int idx = lambda_body(s, tree, 1);
-
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK));
- push();
- }
- break;
-
- case NODE_IF:
- {
- int pos1, pos2;
- node *e = tree->cdr->cdr->car;
-
- codegen(s, tree->car, VAL);
- pop();
- pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
-
- codegen(s, tree->cdr->car, val);
- if (val && !(tree->cdr->car)) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- if (e) {
- if (val) pop();
- pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch(s, pos1);
- codegen(s, e, val);
- dispatch(s, pos2);
- }
- else {
- if (val) {
- pop();
- pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch(s, pos1);
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- dispatch(s, pos2);
- push();
- }
- else {
- dispatch(s, pos1);
- }
- }
- }
- break;
-
- case NODE_AND:
- {
- int pos;
-
- codegen(s, tree->car, VAL);
- pop();
- pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
- codegen(s, tree->cdr, val);
- dispatch(s, pos);
- }
- break;
-
- case NODE_OR:
- {
- int pos;
-
- codegen(s, tree->car, VAL);
- pop();
- pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
- codegen(s, tree->cdr, val);
- dispatch(s, pos);
- }
- break;
-
- case NODE_WHILE:
- {
- struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
-
- lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
- lp->pc2 = new_label(s);
- codegen(s, tree->cdr, NOVAL);
- dispatch(s, lp->pc1);
- codegen(s, tree->car, VAL);
- pop();
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc));
-
- loop_pop(s, val);
- }
- break;
-
- case NODE_UNTIL:
- {
- struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
-
- lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
- lp->pc2 = new_label(s);
- codegen(s, tree->cdr, NOVAL);
- dispatch(s, lp->pc1);
- codegen(s, tree->car, VAL);
- pop();
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc));
-
- loop_pop(s, val);
- }
- break;
-
- case NODE_FOR:
- for_body(s, tree);
- if (val) push();
- break;
-
- case NODE_CASE:
- {
- int head = 0;
- int pos1, pos2, pos3, tmp;
- node *n;
-
- pos3 = 0;
- if (tree->car) {
- head = cursp();
- codegen(s, tree->car, VAL);
- }
- tree = tree->cdr;
- while (tree) {
- n = tree->car->car;
- pos1 = pos2 = 0;
- while (n) {
- codegen(s, n->car, VAL);
- if (head) {
- genop(s, MKOP_AB(OP_MOVE, cursp(), head));
- pop();
- if ((intptr_t)n->car->car == NODE_SPLAT) {
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
- }
- else {
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
- }
- }
- else {
- pop();
- }
- tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
- pos2 = tmp;
- n = n->cdr;
- }
- if (tree->car->car) {
- pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
- dispatch_linked(s, pos2);
- }
- codegen(s, tree->car->cdr, val);
- if (val) pop();
- tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
- pos3 = tmp;
- if (pos1) dispatch(s, pos1);
- tree = tree->cdr;
- }
- if (val) {
- int pos = cursp();
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- if (pos3) dispatch_linked(s, pos3);
- pop();
- genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
- push();
- }
- else if (pos3) {
- dispatch_linked(s, pos3);
- }
- }
- break;
-
- case NODE_SCOPE:
- scope_body(s, tree, NOVAL);
- break;
-
- case NODE_FCALL:
- case NODE_CALL:
- gen_call(s, tree, 0, 0, val);
- break;
-
- case NODE_DOT2:
- codegen(s, tree->car, val);
- codegen(s, tree->cdr, val);
- if (val) {
- pop(); pop();
- genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE));
- push();
- }
- break;
-
- case NODE_DOT3:
- codegen(s, tree->car, val);
- codegen(s, tree->cdr, val);
- if (val) {
- pop(); pop();
- genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE));
- push();
- }
- break;
-
- case NODE_COLON2:
- {
- int sym = new_sym(s, sym(tree->cdr));
-
- codegen(s, tree->car, VAL);
- pop();
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- if (val) push();
- }
- break;
-
- case NODE_COLON3:
- {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- if (val) push();
- }
- break;
-
- case NODE_ARRAY:
- {
- int n;
-
- n = gen_values(s, tree, val);
- if (n >= 0) {
- if (val) {
- pop_n(n);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
- push();
- }
- }
- else if (val) {
- push();
- }
- }
- break;
-
- case NODE_HASH:
- {
- int len = 0;
- mrb_bool update = FALSE;
-
- while (tree) {
- codegen(s, tree->car->car, val);
- codegen(s, tree->car->cdr, val);
- len++;
- tree = tree->cdr;
- if (val && len == 126) {
- pop_n(len*2);
- genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
- if (update) {
- pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
- }
- push();
- update = TRUE;
- len = 0;
- }
- }
- if (val) {
- pop_n(len*2);
- genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
- if (update) {
- pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
- }
- push();
- }
- }
- break;
-
- case NODE_SPLAT:
- codegen(s, tree, VAL);
- break;
-
- case NODE_ASGN:
- codegen(s, tree->cdr, VAL);
- pop();
- gen_assignment(s, tree->car, cursp(), val);
- break;
-
- case NODE_MASGN:
- {
- int len = 0, n = 0, post = 0;
- node *t = tree->cdr, *p;
- int rhs = cursp();
-
- if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) {
- /* fixed rhs */
- t = t->cdr;
- while (t) {
- codegen(s, t->car, VAL);
- len++;
- t = t->cdr;
- }
- tree = tree->car;
- if (tree->car) { /* pre */
- t = tree->car;
- n = 0;
- while (t) {
- gen_assignment(s, t->car, rhs+n, NOVAL);
- n++;
- t = t->cdr;
- }
- }
- t = tree->cdr;
- if (t) {
- if (t->cdr) { /* post count */
- p = t->cdr->car;
- while (p) {
- post++;
- p = p->cdr;
- }
- }
- if (t->car) { /* rest (len - pre - post) */
- int rn = len - post - n;
-
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn));
- gen_assignment(s, t->car, cursp(), NOVAL);
- n += rn;
- }
- if (t->cdr && t->cdr->car) {
- t = t->cdr->car;
- while (n<len) {
- gen_assignment(s, t->car, rhs+n, NOVAL);
- t = t->cdr;
- n++;
- }
- }
- }
- pop_n(len);
- if (val) {
- genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len));
- push();
- }
- }
- else {
- /* variable rhs */
- codegen(s, t, VAL);
- gen_vmassignment(s, tree->car, rhs, val);
- }
- }
- break;
-
- case NODE_OP_ASGN:
- {
- mrb_sym sym = sym(tree->cdr->car);
- mrb_int len;
- const char *name = mrb_sym2name_len(s->mrb, sym, &len);
- int idx;
-
- codegen(s, tree->car, VAL);
- if (len == 2 &&
- ((name[0] == '|' && name[1] == '|') ||
- (name[0] == '&' && name[1] == '&'))) {
- int pos;
-
- pop();
- pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL);
- codegen(s, tree->cdr->cdr->car, VAL);
- pop();
- gen_assignment(s, tree->car, cursp(), val);
- dispatch(s, pos);
- break;
- }
- codegen(s, tree->cdr->cdr->car, VAL);
- push(); pop();
- pop(); pop();
-
- idx = new_msym(s, sym);
- if (len == 1 && name[0] == '+') {
- genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val);
- }
- else if (len == 1 && name[0] == '-') {
- genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val);
- }
- else if (len == 1 && name[0] == '*') {
- genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1));
- }
- else if (len == 1 && name[0] == '/') {
- genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1));
- }
- else if (len == 1 && name[0] == '<') {
- genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1));
- }
- else if (len == 2 && name[0] == '<' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1));
- }
- else if (len == 1 && name[0] == '>') {
- genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1));
- }
- else if (len == 2 && name[0] == '>' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1));
- }
- else {
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1));
- }
- }
- gen_assignment(s, tree->car, cursp(), val);
- break;
-
- case NODE_SUPER:
- {
- int n = 0, noop = 0, sendv = 0;
-
- push(); /* room for receiver */
- if (tree) {
- node *args = tree->car;
- if (args) {
- n = gen_values(s, args, VAL);
- if (n < 0) {
- n = noop = sendv = 1;
- push();
- }
- }
- }
- if (tree && tree->cdr) {
- codegen(s, tree->cdr, VAL);
- pop();
- }
- else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push(); pop();
- }
- pop_n(n+1);
- if (sendv) n = CALL_MAXARGS;
- genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n));
- if (val) push();
- }
- break;
-
- case NODE_ZSUPER:
- {
- codegen_scope *s2 = s;
- int lv = 0, ainfo = 0;
-
- push(); /* room for receiver */
- while (!s2->mscope) {
- lv++;
- s2 = s2->prev;
- if (!s2) break;
- }
- if (s2) ainfo = s2->ainfo;
- genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)));
- push(); push(); pop(); /* ARGARY pushes two values */
- if (tree && tree->cdr) {
- codegen(s, tree->cdr, VAL);
- pop();
- }
- pop(); pop();
- genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS));
- if (val) push();
- }
- break;
-
- case NODE_RETURN:
- if (tree) {
- codegen(s, tree, VAL);
- pop();
- }
- else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- }
- if (s->loop) {
- genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN));
- }
- else {
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
- if (val) push();
- break;
-
- case NODE_YIELD:
- {
- codegen_scope *s2 = s;
- int lv = 0, ainfo = 0;
- int n = 0, sendv = 0;
-
- while (!s2->mscope) {
- lv++;
- s2 = s2->prev;
- if (!s2) break;
- }
- if (s2) ainfo = s2->ainfo;
- genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
- push();
- if (tree) {
- n = gen_values(s, tree, VAL);
- if (n < 0) {
- n = sendv = 1;
- push();
- }
- }
- pop_n(n+1);
- if (sendv) n = CALL_MAXARGS;
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
- if (val) push();
- }
- break;
-
- case NODE_BREAK:
- loop_break(s, tree);
- if (val) push();
- break;
-
- case NODE_NEXT:
- if (!s->loop) {
- raise_error(s, "unexpected next");
- }
- else if (s->loop->type == LOOP_NORMAL) {
- if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
- }
- codegen(s, tree, NOVAL);
- genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc));
- }
- else {
- if (tree) {
- codegen(s, tree, VAL);
- pop();
- }
- else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- }
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
- if (val) push();
- break;
-
- case NODE_REDO:
- if (!s->loop) {
- raise_error(s, "unexpected redo");
- }
- else {
- if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
- }
- genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
- }
- break;
-
- case NODE_RETRY:
- {
- const char *msg = "unexpected retry";
-
- if (!s->loop) {
- raise_error(s, msg);
- }
- else {
- struct loopinfo *lp = s->loop;
- int n = 0;
-
- while (lp && lp->type != LOOP_RESCUE) {
- if (lp->type == LOOP_BEGIN) {
- n++;
- }
- lp = lp->prev;
- }
- if (!lp) {
- raise_error(s, msg);
- }
- else {
- if (n > 0) {
- while (n--) {
- genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
- }
- }
- if (s->ensure_level > lp->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL);
- }
- genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
- }
- }
- }
- break;
-
- case NODE_LVAR:
- if (val) {
- int idx = lv_idx(s, sym(tree));
-
- if (idx > 0) {
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
- }
- else {
- int lv = 0;
- codegen_scope *up = s->prev;
-
- while (up) {
- idx = lv_idx(up, sym(tree));
- if (idx > 0) {
- genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv));
- break;
- }
- lv++;
- up = up->prev;
- }
- }
- push();
- }
- break;
-
- case NODE_GVAR:
- {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
- push();
- }
- break;
-
- case NODE_IVAR:
- {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_ABx(OP_GETIV, cursp(), sym));
- push();
- }
- break;
-
- case NODE_CVAR:
- {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_ABx(OP_GETCV, cursp(), sym));
- push();
- }
- break;
-
- case NODE_CONST:
- {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym));
- push();
- }
- break;
-
- case NODE_DEFINED:
- codegen(s, tree, VAL);
- break;
-
- case NODE_BACK_REF:
- {
- char buf[2] = { '$' };
- mrb_value str;
- int sym;
-
- buf[1] = (char)(intptr_t)tree;
- str = mrb_str_new(s->mrb, buf, 2);
- sym = new_sym(s, mrb_intern_str(s->mrb, str));
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
- push();
- }
- break;
-
- case NODE_NTH_REF:
- {
- int sym;
- mrb_state *mrb = s->mrb;
- mrb_value fix = mrb_fixnum_value((intptr_t)tree);
- mrb_value str = mrb_str_buf_new(mrb, 4);
-
- mrb_str_cat_lit(mrb, str, "$");
- mrb_str_cat_str(mrb, str, mrb_fixnum_to_str(mrb, fix, 10));
- sym = new_sym(s, mrb_intern_str(mrb, str));
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
- push();
- }
- break;
-
- case NODE_ARG:
- /* should not happen */
- break;
-
- case NODE_BLOCK_ARG:
- codegen(s, tree, VAL);
- break;
-
- case NODE_INT:
- if (val) {
- char *p = (char*)tree->car;
- int base = (intptr_t)tree->cdr->car;
- mrb_int i;
- mrb_code co;
- mrb_bool overflow;
-
- i = readint_mrb_int(s, p, base, FALSE, &overflow);
- if (overflow) {
- double f = readint_float(s, p, base);
- int off = new_lit(s, mrb_float_value(s->mrb, f));
-
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
- }
- else {
- if (i < MAXARG_sBx && i > -MAXARG_sBx) {
- co = MKOP_AsBx(OP_LOADI, cursp(), i);
- }
- else {
- int off = new_lit(s, mrb_fixnum_value(i));
- co = MKOP_ABx(OP_LOADL, cursp(), off);
- }
- genop(s, co);
- }
- push();
- }
- break;
-
- case NODE_FLOAT:
- if (val) {
- char *p = (char*)tree;
- mrb_float f = str_to_mrb_float(p);
- int off = new_lit(s, mrb_float_value(s->mrb, f));
-
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
- push();
- }
- break;
-
- case NODE_NEGATE:
- {
- nt = (intptr_t)tree->car;
- tree = tree->cdr;
- switch (nt) {
- case NODE_FLOAT:
- {
- char *p = (char*)tree;
- mrb_float f = str_to_mrb_float(p);
- int off = new_lit(s, mrb_float_value(s->mrb, -f));
-
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
- push();
- }
- break;
-
- case NODE_INT:
- {
- char *p = (char*)tree->car;
- int base = (intptr_t)tree->cdr->car;
- mrb_int i;
- mrb_code co;
- mrb_bool overflow;
-
- i = readint_mrb_int(s, p, base, TRUE, &overflow);
- if (overflow) {
- double f = readint_float(s, p, base);
- int off = new_lit(s, mrb_float_value(s->mrb, -f));
-
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
- }
- else {
- if (i < MAXARG_sBx && i > -MAXARG_sBx) {
- co = MKOP_AsBx(OP_LOADI, cursp(), i);
- }
- else {
- int off = new_lit(s, mrb_fixnum_value(i));
- co = MKOP_ABx(OP_LOADL, cursp(), off);
- }
- genop(s, co);
- }
- push();
- }
- break;
-
- default:
- {
- int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
-
- genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
- push();
- codegen(s, tree, VAL);
- pop(); pop();
- genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
- }
- break;
- }
- }
- break;
-
- case NODE_STR:
- if (val) {
- char *p = (char*)tree->car;
- size_t len = (intptr_t)tree->cdr;
- int ai = mrb_gc_arena_save(s->mrb);
- int off = new_lit(s, mrb_str_new(s->mrb, p, len));
-
- mrb_gc_arena_restore(s->mrb, ai);
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- push();
- }
- break;
-
- case NODE_HEREDOC:
- tree = ((struct mrb_parser_heredoc_info *)tree)->doc;
- /* fall through */
- case NODE_DSTR:
- if (val) {
- node *n = tree;
-
- codegen(s, n->car, VAL);
- n = n->cdr;
- while (n) {
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
- push();
- n = n->cdr;
- }
- }
- else {
- node *n = tree;
-
- while (n) {
- if ((intptr_t)n->car->car != NODE_STR) {
- codegen(s, n->car, NOVAL);
- }
- n = n->cdr;
- }
- }
- break;
-
- case NODE_WORDS:
- gen_literal_array(s, tree, FALSE, val);
- break;
-
- case NODE_SYMBOLS:
- gen_literal_array(s, tree, TRUE, val);
- break;
-
- case NODE_DXSTR:
- {
- node *n;
- int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
-
- if (val == NOVAL) { push(); }
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- push();
- codegen(s, tree->car, VAL);
- n = tree->cdr;
- while (n) {
- if ((intptr_t)n->car->car == NODE_XSTR) {
- n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
- mrb_assert(!n->cdr); /* must be the end */
- }
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
- push();
- n = n->cdr;
- }
- pop();
- pop();
- sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
- if (val == NOVAL) { pop(); }
- else { push(); }
- mrb_gc_arena_restore(s->mrb, ai);
- }
- break;
-
- case NODE_XSTR:
- {
- char *p = (char*)tree->car;
- size_t len = (intptr_t)tree->cdr;
- int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
- int off = new_lit(s, mrb_str_new(s->mrb, p, len));
-
- if (val == NOVAL) { push(); }
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- push();
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- pop();
- sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
- if (val == NOVAL) { pop(); }
- else { push(); }
- mrb_gc_arena_restore(s->mrb, ai);
- }
- break;
-
- case NODE_REGX:
- if (val) {
- char *p1 = (char*)tree->car;
- char *p2 = (char*)tree->cdr;
- int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
- int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1));
- int argc = 1;
-
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- push();
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- if (p2) {
- push();
- off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- argc++;
- pop();
- }
- pop();
- sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
- mrb_gc_arena_restore(s->mrb, ai);
- push();
- }
- break;
-
- case NODE_DREGX:
- if (val) {
- node *n = tree->car;
- int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
- int argc = 1;
- int off;
- char *p;
-
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
- push();
- codegen(s, n->car, VAL);
- n = n->cdr;
- while (n) {
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
- push();
- n = n->cdr;
- }
- n = tree->cdr->cdr;
- if (n->car) {
- p = (char*)n->car;
- off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
- codegen(s, tree->car, VAL);
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
- }
- if (n->cdr) {
- char *p2 = (char*)n->cdr;
- int off;
-
- push();
- off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
- argc++;
- pop();
- }
- pop();
- sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
- mrb_gc_arena_restore(s->mrb, ai);
- push();
- }
- else {
- node *n = tree->car;
-
- while (n) {
- if ((intptr_t)n->car->car != NODE_STR) {
- codegen(s, n->car, NOVAL);
- }
- n = n->cdr;
- }
- }
- break;
-
- case NODE_SYM:
- if (val) {
- int sym = new_sym(s, sym(tree));
-
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
- push();
- }
- break;
-
- case NODE_DSYM:
- codegen(s, tree, val);
- if (val) {
- gen_send_intern(s);
- }
- break;
-
- case NODE_SELF:
- if (val) {
- genop(s, MKOP_A(OP_LOADSELF, cursp()));
- push();
- }
- break;
-
- case NODE_NIL:
- if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- break;
-
- case NODE_TRUE:
- if (val) {
- genop(s, MKOP_A(OP_LOADT, cursp()));
- push();
- }
- break;
-
- case NODE_FALSE:
- if (val) {
- genop(s, MKOP_A(OP_LOADF, cursp()));
- push();
- }
- break;
-
- case NODE_ALIAS:
- {
- int a = new_msym(s, sym(tree->car));
- int b = new_msym(s, sym(tree->cdr));
- int c = new_msym(s, mrb_intern_lit(s->mrb,"alias_method"));
-
- genop(s, MKOP_A(OP_TCLASS, cursp()));
- push();
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a));
- push();
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
- push();
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- pop_n(3);
- genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
- if (val) {
- push();
- }
- }
- break;
-
- case NODE_UNDEF:
- {
- int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
- int num = 0;
- node *t = tree;
-
- genop(s, MKOP_A(OP_TCLASS, cursp()));
- push();
- while (t) {
- int symbol = new_msym(s, sym(t->car));
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
- push();
- t = t->cdr;
- num++;
- }
- pop_n(num + 1);
- genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
- if (val) {
- push();
- }
- }
- break;
-
- case NODE_CLASS:
- {
- int idx;
-
- if (tree->car->car == (node*)0) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- else if (tree->car->car == (node*)1) {
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- push();
- }
- else {
- codegen(s, tree->car->car, VAL);
- }
- if (tree->cdr->car) {
- codegen(s, tree->cdr->car, VAL);
- }
- else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- pop(); pop();
- idx = new_msym(s, sym(tree->car->cdr));
- genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
- idx = scope_body(s, tree->cdr->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
- if (val) {
- push();
- }
- }
- break;
-
- case NODE_MODULE:
- {
- int idx;
-
- if (tree->car->car == (node*)0) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
- }
- else if (tree->car->car == (node*)1) {
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- push();
- }
- else {
- codegen(s, tree->car->car, VAL);
- }
- pop();
- idx = new_msym(s, sym(tree->car->cdr));
- genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
- idx = scope_body(s, tree->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
- if (val) {
- push();
- }
- }
- break;
-
- case NODE_SCLASS:
- {
- int idx;
-
- codegen(s, tree->car, VAL);
- pop();
- genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
- idx = scope_body(s, tree->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
- if (val) {
- push();
- }
- }
- break;
-
- case NODE_DEF:
- {
- int sym = new_msym(s, sym(tree->car));
- int idx = lambda_body(s, tree->cdr, 0);
-
- genop(s, MKOP_A(OP_TCLASS, cursp()));
- push();
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
- push(); pop();
- pop();
- genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
- if (val) {
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
- push();
- }
- }
- break;
-
- case NODE_SDEF:
- {
- node *recv = tree->car;
- int sym = new_msym(s, sym(tree->cdr->car));
- int idx = lambda_body(s, tree->cdr->cdr, 0);
-
- codegen(s, recv, VAL);
- pop();
- genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
- push();
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
- pop();
- genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
- if (val) {
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
- push();
- }
- }
- break;
-
- case NODE_POSTEXE:
- codegen(s, tree, NOVAL);
- break;
-
- default:
- break;
- }
-}
-
-static void
-scope_add_irep(codegen_scope *s, mrb_irep *irep)
-{
- if (s->irep == NULL) {
- s->irep = irep;
- return;
- }
- if (s->irep->rlen == s->rcapa) {
- s->rcapa *= 2;
- s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa);
- }
- s->irep->reps[s->irep->rlen] = irep;
- s->irep->rlen++;
-}
-
-static codegen_scope*
-scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
-{
- static const codegen_scope codegen_scope_zero = { 0 };
- mrb_pool *pool = mrb_pool_open(mrb);
- codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
-
- if (!p) return 0;
- *p = codegen_scope_zero;
- p->mrb = mrb;
- p->mpool = pool;
- if (!prev) return p;
- p->prev = prev;
- p->ainfo = -1;
- p->mscope = 0;
-
- p->irep = mrb_add_irep(mrb);
- scope_add_irep(prev, p->irep);
-
- p->rcapa = 8;
- p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa);
-
- p->icapa = 1024;
- p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa);
- p->irep->iseq = p->iseq;
-
- p->pcapa = 32;
- p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa);
- p->irep->plen = 0;
-
- p->scapa = 256;
- p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
- p->irep->slen = 0;
-
- p->lv = lv;
- p->sp += node_len(lv)+1; /* add self */
- p->nlocals = p->sp;
- if (lv) {
- node *n = lv;
- size_t i = 0;
-
- p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1));
- for (i=0, n=lv; n; i++,n=n->cdr) {
- p->irep->lv[i].name = lv_name(n);
- if (lv_name(n)) {
- p->irep->lv[i].r = lv_idx(p, lv_name(n));
- }
- else {
- p->irep->lv[i].r = 0;
- }
- }
- mrb_assert(i + 1 == p->nlocals);
- }
- p->ai = mrb_gc_arena_save(mrb);
-
- p->filename = prev->filename;
- if (p->filename) {
- p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
- }
- p->lineno = prev->lineno;
-
- /* debug setting */
- p->debug_start_pos = 0;
- if (p->filename) {
- mrb_debug_info_alloc(mrb, p->irep);
- p->irep->filename = p->filename;
- p->irep->lines = p->lines;
- }
- else {
- p->irep->debug_info = NULL;
- }
- p->parser = prev->parser;
- p->filename_index = prev->filename_index;
-
- return p;
-}
-
-static void
-scope_finish(codegen_scope *s)
-{
- mrb_state *mrb = s->mrb;
- mrb_irep *irep = s->irep;
- size_t fname_len;
- char *fname;
-
- irep->flags = 0;
- if (s->iseq) {
- irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
- irep->ilen = s->pc;
- if (s->lines) {
- irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc);
- }
- else {
- irep->lines = 0;
- }
- }
- irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
- irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
- irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
- if (s->filename) {
- s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
- mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc);
-
- fname_len = strlen(s->filename);
- fname = (char*)codegen_malloc(s, fname_len + 1);
- memcpy(fname, s->filename, fname_len);
- fname[fname_len] = '\0';
- irep->filename = fname;
- }
-
- irep->nlocals = s->nlocals;
- irep->nregs = s->nregs;
-
- mrb_gc_arena_restore(mrb, s->ai);
- mrb_pool_close(s->mpool);
-}
-
-static struct loopinfo*
-loop_push(codegen_scope *s, enum looptype t)
-{
- struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo));
-
- p->type = t;
- p->pc1 = p->pc2 = p->pc3 = 0;
- p->prev = s->loop;
- p->ensure_level = s->ensure_level;
- p->acc = cursp();
- s->loop = p;
-
- return p;
-}
-
-static void
-loop_break(codegen_scope *s, node *tree)
-{
- if (!s->loop) {
- codegen(s, tree, NOVAL);
- raise_error(s, "unexpected break");
- }
- else {
- struct loopinfo *loop;
-
- if (tree) {
- codegen(s, tree, VAL);
- pop();
- }
-
- loop = s->loop;
- while (loop->type == LOOP_BEGIN) {
- genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
- loop = loop->prev;
- }
- while (loop->type == LOOP_RESCUE) {
- loop = loop->prev;
- }
- if (loop->type == LOOP_NORMAL) {
- int tmp;
-
- if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
- }
- if (tree) {
- genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
- }
- tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
- loop->pc3 = tmp;
- }
- else {
- genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK));
- }
- }
-}
-
-static void
-loop_pop(codegen_scope *s, int val)
-{
- if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- }
- dispatch_linked(s, s->loop->pc3);
- s->loop = s->loop->prev;
- if (val) push();
-}
-
-#ifdef ENABLE_STDIO
-static int
-print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
-{
- size_t i;
-
- if (n == 0) return 0;
-
- for (i=0; i+1<irep->nlocals; i++) {
- if (irep->lv[i].r == n) {
- mrb_sym sym = irep->lv[i].name;
- if (pre) printf(" ");
- printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym));
- return 1;
- }
- }
- return 0;
-}
-
-#define RA 1
-#define RB 2
-#define RAB 3
-
-static void
-print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r)
-{
- int pre = 0;
-
- if (!irep->lv
- || ((!(r & RA) || GETARG_A(c) >= irep->nlocals)
- && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) {
- printf("\n");
- return;
- }
- printf("\t; ");
- if (r & RA) {
- pre = print_r(mrb, irep, GETARG_A(c), 0);
- }
- if (r & RB) {
- print_r(mrb, irep, GETARG_B(c), pre);
- }
- printf("\n");
-}
-#endif
-
-static void
-codedump(mrb_state *mrb, mrb_irep *irep)
-{
-#ifdef ENABLE_STDIO
- int i;
- int ai;
- mrb_code c;
- const char *file = NULL, *next_file;
- int32_t line;
-
- if (!irep) return;
- printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", irep,
- irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
-
- for (i = 0; i < (int)irep->ilen; i++) {
- ai = mrb_gc_arena_save(mrb);
-
- next_file = mrb_debug_get_filename(irep, i);
- if (next_file && file != next_file) {
- printf("file: %s\n", next_file);
- file = next_file;
- }
- line = mrb_debug_get_line(irep, i);
- if (line < 0) {
- printf(" ");
- }
- else {
- printf("%5d ", line);
- }
-
- printf("%03d ", i);
- c = irep->iseq[i];
- switch (GET_OPCODE(c)) {
- case OP_NOP:
- printf("OP_NOP\n");
- break;
- case OP_MOVE:
- printf("OP_MOVE\tR%d\tR%d", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_LOADL:
- {
- mrb_value v = irep->pool[GETARG_Bx(c)];
- mrb_value s = mrb_inspect(mrb, v);
- printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
- }
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADI:
- printf("OP_LOADI\tR%d\t%d", GETARG_A(c), GETARG_sBx(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADSYM:
- printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADNIL:
- printf("OP_LOADNIL\tR%d\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADSELF:
- printf("OP_LOADSELF\tR%d\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADT:
- printf("OP_LOADT\tR%d\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADF:
- printf("OP_LOADF\tR%d\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETGLOBAL:
- printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETGLOBAL:
- printf("OP_SETGLOBAL\t:%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETCONST:
- printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETCONST:
- printf("OP_SETCONST\t:%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETMCNST:
- printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_SETMCNST:
- printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1,
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETIV:
- printf("OP_GETIV\tR%d\t%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETIV:
- printf("OP_SETIV\t%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETUPVAR:
- printf("OP_GETUPVAR\tR%d\t%d\t%d",
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETUPVAR:
- printf("OP_SETUPVAR\tR%d\t%d\t%d",
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETCV:
- printf("OP_GETCV\tR%d\t%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETCV:
- printf("OP_SETCV\t%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_JMP:
- printf("OP_JMP\t\t%03d\n", i+GETARG_sBx(c));
- break;
- case OP_JMPIF:
- printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
- break;
- case OP_JMPNOT:
- printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
- break;
- case OP_SEND:
- printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SENDB:
- printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_TAILCALL:
- printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUPER:
- printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c),
- GETARG_C(c));
- break;
- case OP_ARGARY:
- printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c),
- (GETARG_Bx(c)>>10)&0x3f,
- (GETARG_Bx(c)>>9)&0x1,
- (GETARG_Bx(c)>>4)&0x1f,
- (GETARG_Bx(c)>>0)&0xf);
- print_lv(mrb, irep, c, RA);
- break;
-
- case OP_ENTER:
- printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
- (GETARG_Ax(c)>>18)&0x1f,
- (GETARG_Ax(c)>>13)&0x1f,
- (GETARG_Ax(c)>>12)&0x1,
- (GETARG_Ax(c)>>7)&0x1f,
- (GETARG_Ax(c)>>2)&0x1f,
- (GETARG_Ax(c)>>1)&0x1,
- GETARG_Ax(c) & 0x1);
- break;
- case OP_RETURN:
- printf("OP_RETURN\tR%d", GETARG_A(c));
- switch (GETARG_B(c)) {
- case OP_R_NORMAL:
- case OP_R_RETURN:
- printf("\treturn"); break;
- case OP_R_BREAK:
- printf("\tbreak"); break;
- default:
- printf("\tbroken"); break;
- break;
- }
- print_lv(mrb, irep, c, RA);
- break;
- case OP_BLKPUSH:
- printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c),
- (GETARG_Bx(c)>>10)&0x3f,
- (GETARG_Bx(c)>>9)&0x1,
- (GETARG_Bx(c)>>4)&0x1f,
- (GETARG_Bx(c)>>0)&0xf);
- print_lv(mrb, irep, c, RA);
- break;
-
- case OP_LAMBDA:
- printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_RANGE:
- printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_METHOD:
- printf("OP_METHOD\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
- break;
-
- case OP_ADD:
- printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_ADDI:
- printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUB:
- printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUBI:
- printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_MUL:
- printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_DIV:
- printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_LT:
- printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_LE:
- printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_GT:
- printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_GE:
- printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_EQ:
- printf("OP_EQ\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
-
- case OP_STOP:
- printf("OP_STOP\n");
- break;
-
- case OP_ARRAY:
- printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_ARYCAT:
- printf("OP_ARYCAT\tR%d\tR%d", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_ARYPUSH:
- printf("OP_ARYPUSH\tR%d\tR%d", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_AREF:
- printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_APOST:
- printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_STRING:
- {
- mrb_value v = irep->pool[GETARG_Bx(c)];
- mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
- printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
- }
- print_lv(mrb, irep, c, RA);
- break;
- case OP_STRCAT:
- printf("OP_STRCAT\tR%d\tR%d", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_HASH:
- printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
- break;
-
- case OP_OCLASS:
- printf("OP_OCLASS\tR%d", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_CLASS:
- printf("OP_CLASS\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_MODULE:
- printf("OP_MODULE\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_EXEC:
- printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1);
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SCLASS:
- printf("OP_SCLASS\tR%d\tR%d", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_TCLASS:
- printf("OP_TCLASS\tR%d", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_ERR:
- {
- mrb_value v = irep->pool[GETARG_Bx(c)];
- mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
- printf("OP_ERR\t%s\n", RSTRING_PTR(s));
- }
- break;
- case OP_EPUSH:
- printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
- break;
- case OP_ONERR:
- printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
- break;
- case OP_RESCUE:
- printf("OP_RESCUE\tR%d", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_RAISE:
- printf("OP_RAISE\tR%d", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_POPERR:
- printf("OP_POPERR\t%d", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_EPOP:
- printf("OP_EPOP\t%d\n", GETARG_A(c));
- break;
-
- default:
- printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c),
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
- break;
- }
- mrb_gc_arena_restore(mrb, ai);
- }
- printf("\n");
-#endif
-}
-
-static void
-codedump_recur(mrb_state *mrb, mrb_irep *irep)
-{
- size_t i;
-
- codedump(mrb, irep);
- for (i=0; i<irep->rlen; i++) {
- codedump_recur(mrb, irep->reps[i]);
- }
-}
-
-void
-mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
-{
- codedump_recur(mrb, proc->body.irep);
-}
-
-struct RProc*
-mrb_generate_code(mrb_state *mrb, parser_state *p)
-{
- codegen_scope *scope = scope_new(mrb, 0, 0);
- struct RProc *proc;
-
- if (!scope) {
- return NULL;
- }
- scope->mrb = mrb;
- scope->parser = p;
- scope->filename = p->filename;
- scope->filename_index = p->current_filename_index;
-
- MRB_TRY(&scope->jmp) {
- /* prepare irep */
- codegen(scope, p->tree, NOVAL);
- proc = mrb_proc_new(mrb, scope->irep);
- mrb_irep_decref(mrb, scope->irep);
- mrb_pool_close(scope->mpool);
- return proc;
- }
- MRB_CATCH(&scope->jmp) {
- if (scope->filename == scope->irep->filename) {
- scope->irep->filename = NULL;
- }
- mrb_irep_decref(mrb, scope->irep);
- mrb_pool_close(scope->mpool);
- return NULL;
- }
- MRB_END_EXC(&scope->jmp);
-}
diff --git a/src/compar.c b/src/compar.c
index 0186b942f..0032fc859 100644
--- a/src/compar.c
+++ b/src/compar.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void
mrb_init_comparable(mrb_state *mrb)
diff --git a/src/debug.c b/src/debug.c
index ea1aa1ddc..cc2d37034 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -1,7 +1,7 @@
#include <string.h>
-#include "mruby.h"
-#include "mruby/irep.h"
-#include "mruby/debug.h"
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/debug.h>
static mrb_irep_debug_info_file *
get_file(mrb_irep_debug_info *info, uint32_t pc)
@@ -49,7 +49,7 @@ select_line_type(const uint16_t *lines, size_t lines_len)
? mrb_debug_line_ary : mrb_debug_line_flat_map;
}
-char const*
+MRB_API char const*
mrb_debug_get_filename(mrb_irep *irep, uint32_t pc)
{
if (irep && pc < irep->ilen) {
@@ -62,7 +62,7 @@ mrb_debug_get_filename(mrb_irep *irep, uint32_t pc)
return NULL;
}
-int32_t
+MRB_API int32_t
mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
{
if (irep && pc < irep->ilen) {
@@ -106,7 +106,7 @@ mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
return -1;
}
-mrb_irep_debug_info *
+MRB_API mrb_irep_debug_info *
mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep)
{
static const mrb_irep_debug_info initial = { 0, 0, NULL };
@@ -119,7 +119,7 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep)
return ret;
}
-mrb_irep_debug_info_file *
+MRB_API mrb_irep_debug_info_file *
mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
uint32_t start_pos, uint32_t end_pos)
{
@@ -198,7 +198,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
return ret;
}
-void
+MRB_API void
mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
{
uint32_t i;
diff --git a/src/dump.c b/src/dump.c
index b820f1a68..ea1cd5596 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -4,16 +4,22 @@
** See Copyright Notice in mruby.h
*/
-#include <ctype.h>
#include <string.h>
#include <limits.h>
-#include "mruby/dump.h"
-#include "mruby/string.h"
-#include "mruby/irep.h"
-#include "mruby/numeric.h"
-#include "mruby/debug.h"
-
-#ifdef ENABLE_STDIO
+#include <mruby/dump.h>
+#include <mruby/string.h>
+#include <mruby/irep.h>
+#include <mruby/numeric.h>
+#include <mruby/debug.h>
+
+#define FLAG_BYTEORDER_NATIVE 2
+#define FLAG_BYTEORDER_NONATIVE 0
+
+#ifdef MRB_USE_FLOAT
+#define MRB_FLOAT_FMT "%.8e"
+#else
+#define MRB_FLOAT_FMT "%.16e"
+#endif
static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
@@ -22,6 +28,17 @@ static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
#endif
static size_t
+write_padding(uint8_t *buf)
+{
+ const size_t align = MRB_DUMP_ALIGNMENT;
+ size_t pad_len = -(intptr_t)buf & (align-1);
+ if (pad_len > 0) {
+ memset(buf, 0, pad_len);
+ }
+ return pad_len;
+}
+
+static size_t
get_irep_header_size(mrb_state *mrb)
{
size_t size = 0;
@@ -37,7 +54,7 @@ write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
{
uint8_t *cur = buf;
- cur += uint32_to_bin(get_irep_record_size_1(mrb, irep), cur); /* record size */
+ cur += uint32_to_bin((uint32_t)get_irep_record_size_1(mrb, irep), cur); /* record size */
cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */
cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */
@@ -52,20 +69,39 @@ get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
size_t size = 0;
size += sizeof(uint32_t); /* ilen */
+ size += sizeof(uint32_t); /* max padding */
size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
return size;
}
static ptrdiff_t
-write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
+write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
{
uint8_t *cur = buf;
uint32_t iseq_no;
cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
- for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
- cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
+ cur += write_padding(cur);
+ switch (flags & DUMP_ENDIAN_NAT) {
+ case DUMP_ENDIAN_BIG:
+ if (bigendian_p()) goto native;
+ for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
+ cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
+ }
+ break;
+ case DUMP_ENDIAN_LIL:
+ if (!bigendian_p()) goto native;
+ for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
+ cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */
+ }
+ break;
+
+ native:
+ case DUMP_ENDIAN_NAT:
+ memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
+ cur += irep->ilen * sizeof(mrb_code);
+ break;
}
return cur - buf;
@@ -78,7 +114,6 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
size_t size = 0;
size_t pool_no;
mrb_value str;
- char buf[32];
size += sizeof(uint32_t); /* plen */
size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */
@@ -97,9 +132,9 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
break;
case MRB_TT_FLOAT:
+ str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
{
- int len;
- len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
+ mrb_int len = RSTRING_LEN(str);
mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
size += (size_t)len;
}
@@ -130,7 +165,6 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
uint16_t len;
mrb_value str;
const char *char_ptr;
- char char_buf[30];
cur += uint32_to_bin(irep->plen, cur); /* number of pool */
@@ -141,43 +175,29 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
case MRB_TT_FIXNUM:
cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
- char_ptr = RSTRING_PTR(str);
- {
- mrb_int tlen;
-
- tlen = RSTRING_LEN(str);
- mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
- len = (uint16_t)tlen;
- }
break;
case MRB_TT_FLOAT:
cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
- {
- int tlen;
- tlen = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
- mrb_assert_int_fit(int, tlen, uint16_t, UINT16_MAX);
- len = (uint16_t)tlen;
- }
- char_ptr = &char_buf[0];
+ str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT);
break;
case MRB_TT_STRING:
cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
- char_ptr = RSTRING_PTR(irep->pool[pool_no]);
- {
- mrb_int tlen;
-
- tlen = RSTRING_LEN(irep->pool[pool_no]);
- mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
- len = (uint16_t)tlen;
- }
+ str = irep->pool[pool_no];
break;
default:
continue;
}
+ char_ptr = RSTRING_PTR(str);
+ {
+ mrb_int tlen = RSTRING_LEN(str);
+ mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
+ len = (uint16_t)tlen;
+ }
+
cur += uint16_to_bin(len, cur); /* data length */
memcpy(cur, char_ptr, (size_t)len);
cur += len;
@@ -263,9 +283,10 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
}
static int
-write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_record_size)
+write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
{
uint32_t i;
+ uint8_t *src = bin;
if (irep == NULL) {
return MRB_DUMP_INVALID_IREP;
@@ -276,10 +297,8 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec
return MRB_DUMP_GENERAL_FAILURE;
}
- memset(bin, 0, *irep_record_size);
-
bin += write_irep_header(mrb, irep, bin);
- bin += write_iseq_block(mrb, irep, bin);
+ bin += write_iseq_block(mrb, irep, bin, flags);
bin += write_pool_block(mrb, irep, bin);
bin += write_syms_block(mrb, irep, bin);
@@ -287,13 +306,13 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec
int result;
size_t rsize;
- result = write_irep_record(mrb, irep->reps[i], bin, &rsize);
+ result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags);
if (result != MRB_DUMP_OK) {
return result;
}
- *irep_record_size += rsize;
bin += rsize;
}
+ *irep_record_size = bin - src;
return MRB_DUMP_OK;
}
@@ -302,7 +321,7 @@ write_footer(mrb_state *mrb, uint8_t *bin)
{
struct rite_binary_footer footer;
- memcpy(footer.section_identify, RITE_BINARY_EOF, sizeof(footer.section_identify));
+ memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident));
uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
memcpy(bin, &footer, sizeof(struct rite_binary_footer));
@@ -315,7 +334,7 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{
struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
- memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
+ memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident));
mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX);
uint32_to_bin((uint32_t)section_size, header->section_size);
@@ -325,10 +344,9 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
}
static int
-write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
+write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
{
int result;
- size_t section_size = 0; /* size of irep record */
size_t rsize = 0;
uint8_t *cur = bin;
@@ -337,14 +355,13 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
}
cur += sizeof(struct rite_section_irep_header);
- section_size += sizeof(struct rite_section_irep_header);
- result = write_irep_record(mrb, irep, cur, &rsize);
+ result = write_irep_record(mrb, irep, cur, &rsize, flags);
if (result != MRB_DUMP_OK) {
return result;
}
- section_size += rsize;
- write_section_irep_header(mrb, section_size, bin);
+ *len_p = cur - bin + rsize;
+ write_section_irep_header(mrb, *len_p, bin);
return MRB_DUMP_OK;
}
@@ -354,7 +371,7 @@ write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{
struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
- memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify));
+ memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident));
uint32_to_bin((uint32_t)section_size, header->section_size);
return MRB_DUMP_OK;
@@ -645,7 +662,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const
dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
section_size += dlen;
- memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
+ memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident));
mrb_assert(section_size <= INT32_MAX);
uint32_to_bin(section_size, header->section_size);
@@ -784,7 +801,7 @@ write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *
goto lv_section_exit;
}
- memcpy(header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(header->section_identify));
+ memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident));
diff = cur - start;
mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
@@ -795,13 +812,28 @@ lv_section_exit:
}
static int
-write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin)
+write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags)
{
struct rite_binary_header *header = (struct rite_binary_header *)bin;
uint16_t crc;
uint32_t offset;
- memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify));
+ switch (flags & DUMP_ENDIAN_NAT) {
+ endian_big:
+ case DUMP_ENDIAN_BIG:
+ memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident));
+ break;
+ endian_little:
+ case DUMP_ENDIAN_LIL:
+ memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident));
+ break;
+
+ case DUMP_ENDIAN_NAT:
+ if (bigendian_p()) goto endian_big;
+ goto endian_little;
+ break;
+ }
+
memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
@@ -841,10 +873,26 @@ is_lv_defined(mrb_irep *irep)
return FALSE;
}
-int
-mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size)
+static uint8_t
+dump_flags(uint8_t flags, uint8_t native)
+{
+ if (native == FLAG_BYTEORDER_NATIVE) {
+ if ((flags & DUMP_ENDIAN_NAT) == 0) {
+ return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT;
+ }
+ return flags;
+ }
+ if ((flags & DUMP_ENDIAN_NAT) == 0) {
+ return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG;
+ }
+ return flags;
+}
+
+static int
+dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
{
int result = MRB_DUMP_GENERAL_FAILURE;
+ size_t malloc_size;
size_t section_irep_size;
size_t section_lineno_size = 0, section_lv_size = 0;
uint8_t *cur = NULL;
@@ -861,7 +909,7 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz
section_irep_size += get_irep_record_size(mrb, irep);
/* DEBUG section size */
- if (debug_info) {
+ if (flags & DUMP_DEBUG_INFO) {
if (debug_info_defined) {
section_lineno_size += sizeof(struct rite_section_debug_header);
/* filename table */
@@ -885,23 +933,23 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz
section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len);
}
- *bin_size = sizeof(struct rite_binary_header) +
- section_irep_size + section_lineno_size + section_lv_size +
- sizeof(struct rite_binary_footer);
- cur = *bin = (uint8_t*)mrb_malloc(mrb, *bin_size);
- if (cur == NULL) {
- goto error_exit;
- }
+ malloc_size = sizeof(struct rite_binary_header) +
+ section_irep_size + section_lineno_size + section_lv_size +
+ sizeof(struct rite_binary_footer);
+ cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size);
cur += sizeof(struct rite_binary_header);
- result = write_section_irep(mrb, irep, cur);
+ result = write_section_irep(mrb, irep, cur, &section_irep_size, flags);
if (result != MRB_DUMP_OK) {
goto error_exit;
}
cur += section_irep_size;
+ *bin_size = sizeof(struct rite_binary_header) +
+ section_irep_size + section_lineno_size + section_lv_size +
+ sizeof(struct rite_binary_footer);
/* write DEBUG section */
- if (debug_info) {
+ if (flags & DUMP_DEBUG_INFO) {
if (debug_info_defined) {
result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
}
@@ -923,24 +971,28 @@ mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, siz
}
write_footer(mrb, cur);
- write_rite_binary_header(mrb, *bin_size, *bin);
+ write_rite_binary_header(mrb, *bin_size, *bin, flags);
error_exit:
if (result != MRB_DUMP_OK) {
mrb_free(mrb, *bin);
*bin = NULL;
}
- if (lv_syms) {
- mrb_free(mrb, lv_syms);
- }
- if (filenames) {
- mrb_free(mrb, filenames);
- }
+ mrb_free(mrb, lv_syms);
+ mrb_free(mrb, filenames);
return result;
}
int
-mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
+mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
+{
+ return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size);
+}
+
+#ifndef MRB_DISABLE_STDIO
+
+int
+mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
{
uint8_t *bin = NULL;
size_t bin_size = 0;
@@ -950,9 +1002,11 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
return MRB_DUMP_INVALID_ARGUMENT;
}
- result = mrb_dump_irep(mrb, irep, debug_info, &bin, &bin_size);
+ result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size);
if (result == MRB_DUMP_OK) {
- fwrite(bin, bin_size, 1, fp);
+ if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
+ result = MRB_DUMP_WRITE_FAULT;
+ }
}
mrb_free(mrb, bin);
@@ -960,45 +1014,82 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
}
static mrb_bool
-is_valid_c_symbol_name(const char *name)
+dump_bigendian_p(uint8_t flags)
{
- const char *c = NULL;
-
- if (name == NULL || name[0] == '\0') return FALSE;
- if (!ISALPHA(name[0]) && name[0] != '_') return FALSE;
-
- c = &name[1];
- for (; *c != '\0'; ++c) {
- if (!ISALNUM(*c) && *c != '_') return FALSE;
- }
-
- return TRUE;
+ switch (flags & DUMP_ENDIAN_NAT) {
+ case DUMP_ENDIAN_BIG:
+ return TRUE;
+ case DUMP_ENDIAN_LIL:
+ return FALSE;
+ default:
+ case DUMP_ENDIAN_NAT:
+ return bigendian_p();
+ }
}
int
-mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, const char *initname)
+mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
{
uint8_t *bin = NULL;
size_t bin_size = 0, bin_idx = 0;
int result;
- if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) {
+ if (fp == NULL || initname == NULL || initname[0] == '\0') {
return MRB_DUMP_INVALID_ARGUMENT;
}
-
- result = mrb_dump_irep(mrb, irep, debug_info, &bin, &bin_size);
+ flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE);
+ result = dump_irep(mrb, irep, flags, &bin, &bin_size);
if (result == MRB_DUMP_OK) {
- fprintf(fp, "#include <stdint.h>\n"); /* for uint8_t under at least Darwin */
- fprintf(fp, "const uint8_t %s[] = {", initname);
+ if (!dump_bigendian_p(flags)) {
+ if (fprintf(fp, "/* dumped in little endian order.\n"
+ " use `mrbc -E` option for big endian CPU. */\n") < 0) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ else {
+ if (fprintf(fp, "/* dumped in big endian order.\n"
+ " use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ if (fprintf(fp,
+ "const uint8_t\n"
+ "#if defined __GNUC__\n"
+ "__attribute__((aligned(%u)))\n"
+ "#elif defined _MSC_VER\n"
+ "__declspec(align(%u))\n"
+ "#endif\n"
+ "%s[] = {",
+ (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
while (bin_idx < bin_size) {
- if (bin_idx % 16 == 0) fputs("\n", fp);
- fprintf(fp, "0x%02x,", bin[bin_idx++]);
+ if (bin_idx % 16 == 0) {
+ if (fputs("\n", fp) == EOF) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
+ }
+ }
+ if (fputs("\n};\n", fp) == EOF) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_WRITE_FAULT;
}
- fputs("\n};\n", fp);
}
mrb_free(mrb, bin);
return result;
}
-#endif /* ENABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO */
diff --git a/src/enum.c b/src/enum.c
index 3def9e860..adb815bf1 100644
--- a/src/enum.c
+++ b/src/enum.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void
mrb_init_enumerable(mrb_state *mrb)
diff --git a/src/error.c b/src/error.c
index 5ca013527..d15f9e76f 100644
--- a/src/error.c
+++ b/src/error.c
@@ -7,27 +7,29 @@
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/irep.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/debug.h"
-#include "mruby/error.h"
-#include "mrb_throw.h"
-
-mrb_value
-mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/irep.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/debug.h>
+#include <mruby/error.h>
+#include <mruby/class.h>
+#include <mruby/throw.h>
+
+MRB_API mrb_value
+mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
{
- return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, mrb_str_new(mrb, ptr, len));
+ mrb_value arg = mrb_str_new(mrb, ptr, len);
+ return mrb_obj_new(mrb, c, 1, &arg);
}
-mrb_value
+MRB_API mrb_value
mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
{
str = mrb_str_to_str(mrb, str);
- return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, str);
+ return mrb_obj_new(mrb, c, 1, &str);
}
/*
@@ -90,8 +92,15 @@ static mrb_value
exc_to_s(mrb_state *mrb, mrb_value exc)
{
mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
+ struct RObject *p;
- if (mrb_nil_p(mesg)) return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
+ if (!mrb_string_p(mesg)) {
+ return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
+ }
+ p = mrb_obj_ptr(mesg);
+ if (!p->c) {
+ p->c = mrb->string_class;
+ }
return mesg;
}
@@ -143,7 +152,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
mrb_str_append(mrb, str, line);
mrb_str_cat_lit(mrb, str, ": ");
if (append_mesg) {
- mrb_str_append(mrb, str, mesg);
+ mrb_str_cat_str(mrb, str, mesg);
mrb_str_cat_lit(mrb, str, " (");
}
mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
@@ -156,7 +165,7 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
str = mrb_str_new_cstr(mrb, cname);
mrb_str_cat_lit(mrb, str, ": ");
if (append_mesg) {
- mrb_str_append(mrb, str, mesg);
+ mrb_str_cat_str(mrb, str, mesg);
}
else {
mrb_str_cat_cstr(mrb, str, cname);
@@ -166,36 +175,6 @@ exc_inspect(mrb_state *mrb, mrb_value exc)
}
-static mrb_value
-exc_equal(mrb_state *mrb, mrb_value exc)
-{
- mrb_value obj;
- mrb_value mesg;
- mrb_bool equal_p;
- mrb_sym id_mesg = mrb_intern_lit(mrb, "mesg");
-
- mrb_get_args(mrb, "o", &obj);
- if (mrb_obj_equal(mrb, exc, obj)) {
- equal_p = TRUE;
- }
- else {
- if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
- if (mrb_respond_to(mrb, obj, mrb_intern_lit(mrb, "message"))) {
- mesg = mrb_funcall(mrb, obj, "message", 0);
- }
- else
- return mrb_false_value();
- }
- else {
- mesg = mrb_attr_get(mrb, obj, id_mesg);
- }
-
- equal_p = mrb_equal(mrb, mrb_attr_get(mrb, exc, id_mesg), mesg);
- }
-
- return mrb_bool_value(equal_p);
-}
-
static void
exc_debug_info(mrb_state *mrb, struct RObject *exc)
{
@@ -223,11 +202,11 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
}
}
-mrb_noreturn void
+MRB_API mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
mrb->exc = mrb_obj_ptr(exc);
- if (!mrb->out_of_memory) {
+ if (!mrb->gc.out_of_memory) {
exc_debug_info(mrb, mrb->exc);
}
if (!mrb->jmp) {
@@ -237,7 +216,7 @@ mrb_exc_raise(mrb_state *mrb, mrb_value exc)
MRB_THROW(mrb->jmp);
}
-mrb_noreturn void
+MRB_API mrb_noreturn void
mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
{
mrb_value mesg;
@@ -245,7 +224,7 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
}
-mrb_value
+MRB_API mrb_value
mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
{
const char *p = format;
@@ -282,11 +261,11 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
else {
size = p - b;
mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
- return mrb_ary_join(mrb, ary, mrb_str_new(mrb,NULL,0));
+ return mrb_ary_join(mrb, ary, mrb_str_new(mrb, NULL, 0));
}
}
-mrb_value
+MRB_API mrb_value
mrb_format(mrb_state *mrb, const char *format, ...)
{
va_list ap;
@@ -299,7 +278,7 @@ mrb_format(mrb_state *mrb, const char *format, ...)
return str;
}
-mrb_noreturn void
+MRB_API mrb_noreturn void
mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
{
va_list args;
@@ -311,7 +290,7 @@ mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
}
-mrb_noreturn void
+MRB_API mrb_noreturn void
mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
{
mrb_value exc;
@@ -327,10 +306,10 @@ mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
mrb_exc_raise(mrb, exc);
}
-void
+MRB_API void
mrb_warn(mrb_state *mrb, const char *fmt, ...)
{
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
va_list ap;
mrb_value str;
@@ -342,10 +321,10 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...)
#endif
}
-mrb_noreturn void
+MRB_API mrb_noreturn void
mrb_bug(mrb_state *mrb, const char *fmt, ...)
{
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
va_list ap;
mrb_value str;
@@ -417,13 +396,13 @@ exception_call:
return mesg;
}
-mrb_value
+MRB_API mrb_value
mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
{
return make_exception(mrb, argc, argv, TRUE);
}
-void
+MRB_API void
mrb_sys_fail(mrb_state *mrb, const char *mesg)
{
struct RClass *sce;
@@ -444,16 +423,15 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg)
}
}
-mrb_noreturn void
-mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...)
+MRB_API mrb_noreturn void
+mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
{
mrb_value exc;
va_list ap;
va_start(ap, fmt);
exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
- mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id),
- mrb_ary_new_from_values(mrb, argc, argv));
+ mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), args);
va_end(ap);
mrb_exc_raise(mrb, exc);
}
@@ -464,10 +442,10 @@ mrb_init_exception(mrb_state *mrb)
struct RClass *exception, *runtime_error, *script_error;
mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
+ MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
- mrb_define_method(mrb, exception, "==", exc_equal, MRB_ARGS_REQ(1));
mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
@@ -475,7 +453,8 @@ mrb_init_exception(mrb_state *mrb)
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
- mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory")));
+ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory"));
script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
+ mrb_define_class(mrb, "SystemStackError", exception);
}
diff --git a/src/error.h b/src/error.h
index 0e0dacf63..eb755ec7f 100644
--- a/src/error.h
+++ b/src/error.h
@@ -1,3 +1,3 @@
/* this header file is to be removed soon.
added for compatibility purpose (1.0.0) */
-#include "mruby/error.h"
+#include <mruby/error.h>
diff --git a/src/etc.c b/src/etc.c
index bc5d116a0..0ad56fe96 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -4,14 +4,14 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/string.h"
-#include "mruby/data.h"
-#include "mruby/class.h"
-#include "mruby/re.h"
-#include "mruby/irep.h"
-
-struct RData*
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/data.h>
+#include <mruby/class.h>
+#include <mruby/re.h>
+#include <mruby/irep.h>
+
+MRB_API struct RData*
mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
{
struct RData *data;
@@ -23,10 +23,10 @@ mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb
return data;
}
-void
+MRB_API void
mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
- if (mrb_special_const_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) {
+ if (mrb_type(obj) != MRB_TT_DATA) {
mrb_check_type(mrb, obj, MRB_TT_DATA);
}
if (DATA_TYPE(obj) != type) {
@@ -45,10 +45,10 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
}
}
-void *
+MRB_API void*
mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
- if (mrb_special_const_p(obj) || (mrb_type(obj) != MRB_TT_DATA)) {
+ if (mrb_type(obj) != MRB_TT_DATA) {
return NULL;
}
if (DATA_TYPE(obj) != type) {
@@ -57,27 +57,25 @@ mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
return DATA_PTR(obj);
}
-void *
+MRB_API void*
mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
{
mrb_data_check_type(mrb, obj, type);
return DATA_PTR(obj);
}
-mrb_sym
+MRB_API mrb_sym
mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
{
- mrb_value tmp;
mrb_sym id;
switch (mrb_type(name)) {
default:
- tmp = mrb_check_string_type(mrb, name);
- if (mrb_nil_p(tmp)) {
- tmp = mrb_inspect(mrb, name);
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp);
+ name = mrb_check_string_type(mrb, name);
+ if (mrb_nil_p(name)) {
+ name = mrb_inspect(mrb, name);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name);
}
- name = tmp;
/* fall through */
case MRB_TT_STRING:
name = mrb_str_intern(mrb, name);
@@ -88,7 +86,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
return id;
}
-mrb_int
+MRB_API mrb_int
mrb_float_id(mrb_float f)
{
const char *p = (const char*)&f;
@@ -104,7 +102,7 @@ mrb_float_id(mrb_float f)
return id;
}
-mrb_int
+MRB_API mrb_int
mrb_obj_id(mrb_value obj)
{
mrb_int tt = mrb_type(obj);
@@ -113,42 +111,42 @@ mrb_obj_id(mrb_value obj)
#define MakeID(p) MakeID2(p,tt)
switch (tt) {
- case MRB_TT_FREE:
- case MRB_TT_UNDEF:
+ case MRB_TT_FREE:
+ case MRB_TT_UNDEF:
return MakeID(0); /* not define */
- case MRB_TT_FALSE:
+ case MRB_TT_FALSE:
if (mrb_nil_p(obj))
return MakeID(1);
return MakeID(0);
- case MRB_TT_TRUE:
+ case MRB_TT_TRUE:
return MakeID(1);
- case MRB_TT_SYMBOL:
+ case MRB_TT_SYMBOL:
return MakeID(mrb_symbol(obj));
- case MRB_TT_FIXNUM:
+ case MRB_TT_FIXNUM:
return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT);
- case MRB_TT_FLOAT:
+ case MRB_TT_FLOAT:
return MakeID(mrb_float_id(mrb_float(obj)));
- case MRB_TT_STRING:
- case MRB_TT_OBJECT:
- case MRB_TT_CLASS:
- case MRB_TT_MODULE:
- case MRB_TT_ICLASS:
- case MRB_TT_SCLASS:
- case MRB_TT_PROC:
- case MRB_TT_ARRAY:
- case MRB_TT_HASH:
- case MRB_TT_RANGE:
- case MRB_TT_EXCEPTION:
- case MRB_TT_FILE:
- case MRB_TT_DATA:
+ case MRB_TT_STRING:
+ case MRB_TT_OBJECT:
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ case MRB_TT_ICLASS:
+ case MRB_TT_SCLASS:
+ case MRB_TT_PROC:
+ case MRB_TT_ARRAY:
+ case MRB_TT_HASH:
+ case MRB_TT_RANGE:
+ case MRB_TT_EXCEPTION:
+ case MRB_TT_FILE:
+ case MRB_TT_DATA:
default:
return MakeID(mrb_ptr(obj));
}
}
#ifdef MRB_WORD_BOXING
-mrb_value
-mrb_float_value(mrb_state *mrb, mrb_float f)
+MRB_API mrb_value
+mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
{
mrb_value v;
@@ -157,8 +155,8 @@ mrb_float_value(mrb_state *mrb, mrb_float f)
return v;
}
-mrb_value
-mrb_float_pool(mrb_state *mrb, mrb_float f)
+MRB_API mrb_value
+mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f)
{
struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat));
nf->tt = MRB_TT_FLOAT;
@@ -167,8 +165,8 @@ mrb_float_pool(mrb_state *mrb, mrb_float f)
return mrb_obj_value(nf);
}
-mrb_value
-mrb_cptr_value(mrb_state *mrb, void *p)
+MRB_API mrb_value
+mrb_word_boxing_cptr_value(mrb_state *mrb, void *p)
{
mrb_value v;
@@ -178,8 +176,45 @@ mrb_cptr_value(mrb_state *mrb, void *p)
}
#endif /* MRB_WORD_BOXING */
-mrb_bool
+MRB_API mrb_bool
mrb_regexp_p(mrb_state *mrb, mrb_value v)
{
return mrb_class_defined(mrb, REGEXP_CLASS) && mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS));
}
+
+#if defined _MSC_VER && _MSC_VER < 1900
+
+#ifndef va_copy
+static void
+mrb_msvc_va_copy(va_list *dest, va_list src)
+{
+ *dest = src;
+}
+#define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src)
+#endif
+
+MRB_API int
+mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg)
+{
+ int cnt;
+ va_list argcp;
+ va_copy(argcp, arg);
+ if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) {
+ cnt = _vscprintf(format, arg);
+ }
+ va_end(argcp);
+ return cnt;
+}
+
+MRB_API int
+mrb_msvc_snprintf(char *s, size_t n, const char *format, ...)
+{
+ va_list arg;
+ int ret;
+ va_start(arg, format);
+ ret = mrb_msvc_vsnprintf(s, n, format, arg);
+ va_end(arg);
+ return ret;
+}
+
+#endif /* defined _MSC_VER && _MSC_VER < 1900 */
diff --git a/src/fmt_fp.c b/src/fmt_fp.c
new file mode 100644
index 000000000..61c7a4cc9
--- /dev/null
+++ b/src/fmt_fp.c
@@ -0,0 +1,371 @@
+/*
+
+Most code in this file originates from musl (src/stdio/vfprintf.c)
+which, just like mruby itself, is licensed under the MIT license.
+
+Copyright (c) 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <math.h>
+#include <float.h>
+#include <ctype.h>
+
+#include <mruby.h>
+#include <mruby/string.h>
+
+struct fmt_args {
+ mrb_state *mrb;
+ mrb_value str;
+};
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM (1U<<('#'-' '))
+#define ZERO_PAD (1U<<('0'-' '))
+#define LEFT_ADJ (1U<<('-'-' '))
+#define PAD_POS (1U<<(' '-' '))
+#define MARK_POS (1U<<('+'-' '))
+
+static void
+out(struct fmt_args *f, const char *s, size_t l)
+{
+ mrb_str_cat(f->mrb, f->str, s, l);
+}
+
+#define PAD_SIZE 256
+static void
+pad(struct fmt_args *f, char c, int w, int l, int fl)
+{
+ char pad[PAD_SIZE];
+ if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
+ l = w - l;
+ memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l);
+ for (; l >= PAD_SIZE; l -= PAD_SIZE)
+ out(f, pad, PAD_SIZE);
+ out(f, pad, l);
+}
+
+static const char xdigits[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static char*
+fmt_u(uint32_t x, char *s)
+{
+ for (; x; x /= 10) *--s = '0' + x % 10;
+ return s;
+}
+
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+
+static int
+fmt_fp(struct fmt_args *f, long double y, int w, int p, int fl, int t)
+{
+ uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
+ uint32_t *a, *d, *r, *z;
+ uint32_t i;
+ int e2=0, e, j, l;
+ char buf[9+LDBL_MANT_DIG/4], *s;
+ const char *prefix="-0X+0X 0X-0x+0x 0x";
+ int pl;
+ char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
+
+ pl=1;
+ if (signbit(y)) {
+ y=-y;
+ } else if (fl & MARK_POS) {
+ prefix+=3;
+ } else if (fl & PAD_POS) {
+ prefix+=6;
+ } else prefix++, pl=0;
+
+ if (!isfinite(y)) {
+ const char *ss = (t&32)?"inf":"INF";
+ if (y!=y) ss=(t&32)?"nan":"NAN";
+ pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
+ out(f, prefix, pl);
+ out(f, ss, 3);
+ pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
+ return MAX(w, 3+pl);
+ }
+
+ y = frexp((double)y, &e2) * 2;
+ if (y) e2--;
+
+ if ((t|32)=='a') {
+ long double round = 8.0;
+ int re;
+
+ if (t&32) prefix += 9;
+ pl += 2;
+
+ if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+ else re=LDBL_MANT_DIG/4-1-p;
+
+ if (re) {
+ while (re--) round*=16;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ }
+ else {
+ y+=round;
+ y-=round;
+ }
+ }
+
+ estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
+ if (estr==ebuf) *--estr='0';
+ *--estr = (e2<0 ? '-' : '+');
+ *--estr = t+('p'-'a');
+
+ s=buf;
+ do {
+ int x=(int)y;
+ *s++=xdigits[x]|(t&32);
+ y=16*(y-x);
+ if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+ } while (y);
+
+ if (p && s-buf-2 < p)
+ l = (p+2) + (ebuf-estr);
+ else
+ l = (s-buf) + (ebuf-estr);
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+ out(f, buf, s-buf);
+ pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
+ out(f, estr, ebuf-estr);
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+ return MAX(w, pl+l);
+ }
+ if (p<0) p=6;
+
+ if (y) y *= 268435456.0, e2-=28;
+
+ if (e2<0) a=r=z=big;
+ else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+ do {
+ *z = (uint32_t)y;
+ y = 1000000000*(y-*z++);
+ } while (y);
+
+ while (e2>0) {
+ uint32_t carry=0;
+ int sh=MIN(29,e2);
+ for (d=z-1; d>=a; d--) {
+ uint64_t x = ((uint64_t)*d<<sh)+carry;
+ *d = x % 1000000000;
+ carry = (uint32_t)(x / 1000000000);
+ }
+ if (carry) *--a = carry;
+ while (z>a && !z[-1]) z--;
+ e2-=sh;
+ }
+ while (e2<0) {
+ uint32_t carry=0, *b;
+ int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9;
+ for (d=a; d<z; d++) {
+ uint32_t rm = *d & ((1<<sh)-1);
+ *d = (*d>>sh) + carry;
+ carry = (1000000000>>sh) * rm;
+ }
+ if (!*a) a++;
+ if (carry) *z++ = carry;
+ /* Avoid (slow!) computation past requested precision */
+ b = (t|32)=='f' ? r : a;
+ if (z-b > need) z = b+need;
+ e2+=sh;
+ }
+
+ if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ else e=0;
+
+ /* Perform rounding: j is precision after the radix (possibly neg) */
+ j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
+ if (j < 9*(z-r-1)) {
+ uint32_t x;
+ /* We avoid C's broken division of negative numbers */
+ d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
+ j += 9*LDBL_MAX_EXP;
+ j %= 9;
+ for (i=10, j++; j<9; i*=10, j++);
+ x = *d % i;
+ /* Are there any significant digits past j? */
+ if (x || d+1!=z) {
+ long double round = 2/LDBL_EPSILON;
+ long double small;
+ if (*d/i & 1) round += 2;
+ if (x<i/2) small=0.5;
+ else if (x==i/2 && d+1==z) small=1.0;
+ else small=1.5;
+ if (pl && *prefix=='-') round*=-1, small*=-1;
+ *d -= x;
+ /* Decide whether to round by probing round+small */
+ if (round+small != round) {
+ *d = *d + i;
+ while (*d > 999999999) {
+ *d--=0;
+ if (d<a) *--a=0;
+ (*d)++;
+ }
+ for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ }
+ }
+ if (z>d+1) z=d+1;
+ }
+ for (; z>a && !z[-1]; z--);
+
+ if ((t|32)=='g') {
+ if (!p) p++;
+ if (p>e && e>=-4) {
+ t--;
+ p-=e+1;
+ }
+ else {
+ t-=2;
+ p--;
+ }
+ if (!(fl&ALT_FORM)) {
+ /* Count trailing zeros in last place */
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ else j=9;
+ if ((t|32)=='f')
+ p = MIN(p,MAX(0,9*(z-r-1)-j));
+ else
+ p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ }
+ }
+ l = 1 + p + (p || (fl&ALT_FORM));
+ if ((t|32)=='f') {
+ if (e>0) l+=e;
+ }
+ else {
+ estr=fmt_u(e<0 ? -e : e, ebuf);
+ while(ebuf-estr<2) *--estr='0';
+ *--estr = (e<0 ? '-' : '+');
+ *--estr = t;
+ l += ebuf-estr;
+ }
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+
+ if ((t|32)=='f') {
+ if (a>r) a=r;
+ for (d=a; d<=r; d++) {
+ char *ss = fmt_u(*d, buf+9);
+ if (d!=a) while (ss>buf) *--ss='0';
+ else if (ss==buf+9) *--ss='0';
+ out(f, ss, buf+9-ss);
+ }
+ if (p || (fl&ALT_FORM)) out(f, ".", 1);
+ for (; d<z && p>0; d++, p-=9) {
+ char *ss = fmt_u(*d, buf+9);
+ while (ss>buf) *--ss='0';
+ out(f, ss, MIN(9,p));
+ }
+ pad(f, '0', p+9, 9, 0);
+ }
+ else {
+ if (z<=a) z=a+1;
+ for (d=a; d<z && p>=0; d++) {
+ char *ss = fmt_u(*d, buf+9);
+ if (ss==buf+9) *--ss='0';
+ if (d!=a) while (ss>buf) *--ss='0';
+ else {
+ out(f, ss++, 1);
+ if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
+ }
+ out(f, ss, MIN(buf+9-ss, p));
+ p -= buf+9-ss;
+ }
+ pad(f, '0', p+18, 18, 0);
+ out(f, estr, ebuf-estr);
+ }
+
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+
+ return MAX(w, pl+l);
+}
+
+static int
+fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo)
+{
+ int p;
+
+ if (*fmt != '%') {
+ return -1;
+ }
+ ++fmt;
+
+ if (*fmt == '.') {
+ ++fmt;
+ for (p = 0; ISDIGIT(*fmt); ++fmt) {
+ p = 10 * p + (*fmt - '0');
+ }
+ }
+ else {
+ p = -1;
+ }
+
+ switch (*fmt) {
+ case 'e': case 'f': case 'g': case 'a':
+ case 'E': case 'F': case 'G': case 'A':
+ return fmt_fp(f, flo, 0, p, 0, *fmt);
+ default:
+ return -1;
+ }
+}
+
+mrb_value
+mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
+{
+ struct fmt_args f;
+
+ f.mrb = mrb;
+ f.str = mrb_str_buf_new(mrb, 24);
+ if (fmt_core(&f, fmt, mrb_float(flo)) < 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string");
+ }
+ return f.str;
+}
diff --git a/src/gc.c b/src/gc.c
index 6eb9808e3..02e058f88 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -6,16 +6,17 @@
#include <string.h>
#include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/data.h"
-#include "mruby/hash.h"
-#include "mruby/proc.h"
-#include "mruby/range.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/gc.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/proc.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/gc.h>
+#include <mruby/error.h>
/*
= Tri-color Incremental Garbage Collection
@@ -62,12 +63,13 @@
== Write Barrier
- mruby implementer and C extension library writer must write a write
- barrier when writing a pointer to an object on object's field.
- Two different write barrier are available:
+ mruby implementer and C extension library writer must insert a write
+ barrier when updating a reference from a field of an object.
+ When updating a reference from a field of object A to object B,
+ two different types of write barrier are available:
- * mrb_field_write_barrier
- * mrb_write_barrier
+ * mrb_field_write_barrier - target B object for a mark.
+ * mrb_write_barrier - target A object for a mark.
== Generational Mode
@@ -107,6 +109,11 @@ typedef struct {
struct RRange range;
struct RData data;
struct RProc proc;
+ struct RException exc;
+#ifdef MRB_WORD_BOXING
+ struct RFloat floatv;
+ struct RCptr cptr;
+#endif
} as;
} RVALUE;
@@ -129,7 +136,7 @@ gettimeofday_time(void)
#define GC_INVOKE_TIME_REPORT(with) do {\
fprintf(stderr, "%s\n", with);\
fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
- fprintf(stderr, "is_generational: %d\n", is_generational(mrb));\
+ fprintf(stderr, "is_generational: %d\n", is_generational(gc));\
fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
} while(0)
@@ -140,10 +147,10 @@ gettimeofday_time(void)
#define GC_TIME_STOP_AND_REPORT do {\
gc_time = gettimeofday_time() - gc_time;\
gc_total_time += gc_time;\
- fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
- fprintf(stderr, "live: %zu\n", mrb->live);\
- fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
- fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
+ fprintf(stderr, "gc_state: %d\n", gc->state);\
+ fprintf(stderr, "live: %zu\n", gc->live);\
+ fprintf(stderr, "majorgc_old_threshold: %zu\n", gc->majorgc_old_threshold);\
+ fprintf(stderr, "gc_threshold: %zu\n", gc->threshold);\
fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
} while(0)
@@ -159,59 +166,82 @@ gettimeofday_time(void)
#define DEBUG(x)
#endif
-#define GC_STEP_SIZE 1024
+#ifndef MRB_HEAP_PAGE_SIZE
+#define MRB_HEAP_PAGE_SIZE 1024
+#endif
+#define GC_STEP_SIZE 1024
-void*
+/* white: 011, black: 100, gray: 000 */
+#define GC_GRAY 0
+#define GC_WHITE_A 1
+#define GC_WHITE_B (1 << 1)
+#define GC_BLACK (1 << 2)
+#define GC_WHITES (GC_WHITE_A | GC_WHITE_B)
+#define GC_COLOR_MASK 7
+
+#define paint_gray(o) ((o)->color = GC_GRAY)
+#define paint_black(o) ((o)->color = GC_BLACK)
+#define paint_white(o) ((o)->color = GC_WHITES)
+#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part)
+#define is_gray(o) ((o)->color == GC_GRAY)
+#define is_white(o) ((o)->color & GC_WHITES)
+#define is_black(o) ((o)->color & GC_BLACK)
+#define flip_white_part(s) ((s)->current_white_part = other_white_part(s))
+#define other_white_part(s) ((s)->current_white_part ^ GC_WHITES)
+#define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE)
+
+#define objects(p) ((RVALUE *)p->objects)
+
+MRB_API void*
mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
{
void *p2;
- p2 = (mrb->allocf)(mrb, p, len, mrb->ud);
- if (!p2 && len > 0 && mrb->heaps) {
+ p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
+ if (!p2 && len > 0 && mrb->gc.heaps) {
mrb_full_gc(mrb);
- p2 = (mrb->allocf)(mrb, p, len, mrb->ud);
+ p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
}
return p2;
}
-
-void*
+MRB_API void*
mrb_realloc(mrb_state *mrb, void *p, size_t len)
{
void *p2;
p2 = mrb_realloc_simple(mrb, p, len);
if (!p2 && len) {
- if (mrb->out_of_memory) {
+ if (mrb->gc.out_of_memory) {
/* mrb_panic(mrb); */
}
else {
- mrb->out_of_memory = TRUE;
+ mrb->gc.out_of_memory = TRUE;
mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
}
}
else {
- mrb->out_of_memory = FALSE;
+ mrb->gc.out_of_memory = FALSE;
}
return p2;
}
-void*
+MRB_API void*
mrb_malloc(mrb_state *mrb, size_t len)
{
return mrb_realloc(mrb, 0, len);
}
-void*
+MRB_API void*
mrb_malloc_simple(mrb_state *mrb, size_t len)
{
return mrb_realloc_simple(mrb, 0, len);
}
-void*
+MRB_API void*
mrb_calloc(mrb_state *mrb, size_t nelem, size_t len)
{
void *p;
@@ -220,11 +250,9 @@ mrb_calloc(mrb_state *mrb, size_t nelem, size_t len)
nelem <= SIZE_MAX / len) {
size_t size;
size = nelem * len;
- p = mrb_realloc(mrb, 0, size);
+ p = mrb_malloc(mrb, size);
- if (p) {
- memset(p, 0, size);
- }
+ memset(p, 0, size);
}
else {
p = NULL;
@@ -233,107 +261,104 @@ mrb_calloc(mrb_state *mrb, size_t nelem, size_t len)
return p;
}
-void
+MRB_API void
mrb_free(mrb_state *mrb, void *p)
{
- (mrb->allocf)(mrb, p, 0, mrb->ud);
+ (mrb->allocf)(mrb, p, 0, mrb->allocf_ud);
}
-#ifndef MRB_HEAP_PAGE_SIZE
-#define MRB_HEAP_PAGE_SIZE 1024
-#endif
-
-struct heap_page {
- struct RBasic *freelist;
- struct heap_page *prev;
- struct heap_page *next;
- struct heap_page *free_next;
- struct heap_page *free_prev;
- mrb_bool old:1;
- RVALUE objects[MRB_HEAP_PAGE_SIZE];
-};
+MRB_API mrb_bool
+mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) {
+ return is_dead(&mrb->gc, object);
+}
static void
-link_heap_page(mrb_state *mrb, struct heap_page *page)
+link_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
- page->next = mrb->heaps;
- if (mrb->heaps)
- mrb->heaps->prev = page;
- mrb->heaps = page;
+ page->next = gc->heaps;
+ if (gc->heaps)
+ gc->heaps->prev = page;
+ gc->heaps = page;
}
static void
-unlink_heap_page(mrb_state *mrb, struct heap_page *page)
+unlink_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
if (page->prev)
page->prev->next = page->next;
if (page->next)
page->next->prev = page->prev;
- if (mrb->heaps == page)
- mrb->heaps = page->next;
+ if (gc->heaps == page)
+ gc->heaps = page->next;
page->prev = NULL;
page->next = NULL;
}
static void
-link_free_heap_page(mrb_state *mrb, struct heap_page *page)
+link_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
- page->free_next = mrb->free_heaps;
- if (mrb->free_heaps) {
- mrb->free_heaps->free_prev = page;
+ page->free_next = gc->free_heaps;
+ if (gc->free_heaps) {
+ gc->free_heaps->free_prev = page;
}
- mrb->free_heaps = page;
+ gc->free_heaps = page;
}
static void
-unlink_free_heap_page(mrb_state *mrb, struct heap_page *page)
+unlink_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
{
if (page->free_prev)
page->free_prev->free_next = page->free_next;
if (page->free_next)
page->free_next->free_prev = page->free_prev;
- if (mrb->free_heaps == page)
- mrb->free_heaps = page->free_next;
+ if (gc->free_heaps == page)
+ gc->free_heaps = page->free_next;
page->free_prev = NULL;
page->free_next = NULL;
}
static void
-add_heap(mrb_state *mrb)
+add_heap(mrb_state *mrb, mrb_gc *gc)
{
- struct heap_page *page = (struct heap_page *)mrb_calloc(mrb, 1, sizeof(struct heap_page));
+ mrb_heap_page *page = (mrb_heap_page *)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE));
RVALUE *p, *e;
struct RBasic *prev = NULL;
- for (p = page->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
p->as.free.tt = MRB_TT_FREE;
p->as.free.next = prev;
prev = &p->as.basic;
}
page->freelist = prev;
- link_heap_page(mrb, page);
- link_free_heap_page(mrb, page);
+ link_heap_page(gc, page);
+ link_free_heap_page(gc, page);
}
#define DEFAULT_GC_INTERVAL_RATIO 200
#define DEFAULT_GC_STEP_RATIO 200
#define DEFAULT_MAJOR_GC_INC_RATIO 200
-#define is_generational(mrb) ((mrb)->is_generational_gc_mode)
-#define is_major_gc(mrb) (is_generational(mrb) && (mrb)->gc_full)
-#define is_minor_gc(mrb) (is_generational(mrb) && !(mrb)->gc_full)
+#define is_generational(gc) ((gc)->generational)
+#define is_major_gc(gc) (is_generational(gc) && (gc)->full)
+#define is_minor_gc(gc) (is_generational(gc) && !(gc)->full)
void
-mrb_init_heap(mrb_state *mrb)
+mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
{
- mrb->heaps = NULL;
- mrb->free_heaps = NULL;
- add_heap(mrb);
- mrb->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
- mrb->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
+#ifndef MRB_GC_FIXED_ARENA
+ gc->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
+ gc->arena_capa = MRB_GC_ARENA_SIZE;
+#endif
+
+ gc->current_white_part = GC_WHITE_A;
+ gc->heaps = NULL;
+ gc->free_heaps = NULL;
+ add_heap(mrb, gc);
+ gc->interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
+ gc->step_ratio = DEFAULT_GC_STEP_RATIO;
#ifndef MRB_GC_TURN_OFF_GENERATIONAL
- mrb->is_generational_gc_mode = TRUE;
- mrb->gc_full = TRUE;
+ gc->generational = TRUE;
+ gc->full = TRUE;
#endif
#ifdef GC_PROFILE
@@ -344,16 +369,16 @@ mrb_init_heap(mrb_state *mrb)
static void obj_free(mrb_state *mrb, struct RBasic *obj);
void
-mrb_free_heap(mrb_state *mrb)
+free_heap(mrb_state *mrb, mrb_gc *gc)
{
- struct heap_page *page = mrb->heaps;
- struct heap_page *tmp;
+ mrb_heap_page *page = gc->heaps;
+ mrb_heap_page *tmp;
RVALUE *p, *e;
while (page) {
tmp = page;
page = page->next;
- for (p = tmp->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
+ for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
if (p->as.free.tt != MRB_TT_FREE)
obj_free(mrb, &p->as.basic);
}
@@ -361,65 +386,123 @@ mrb_free_heap(mrb_state *mrb)
}
}
+void
+mrb_gc_destroy(mrb_state *mrb, mrb_gc *gc)
+{
+ free_heap(mrb, gc);
+#ifndef MRB_GC_FIXED_ARENA
+ mrb_free(mrb, gc->arena);
+#endif
+}
+
static void
-gc_protect(mrb_state *mrb, struct RBasic *p)
+gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
{
#ifdef MRB_GC_FIXED_ARENA
- if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) {
+ if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
/* arena overflow error */
- mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
+ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
}
#else
- if (mrb->arena_idx >= mrb->arena_capa) {
+ if (gc->arena_idx >= gc->arena_capa) {
/* extend arena */
- mrb->arena_capa = (int)(mrb->arena_capa * 1.5);
- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa);
+ gc->arena_capa = (int)(gc->arena_capa * 1.5);
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*gc->arena_capa);
}
#endif
- mrb->arena[mrb->arena_idx++] = p;
+ gc->arena[gc->arena_idx++] = p;
}
-void
+/* mrb_gc_protect() leaves the object in the arena */
+MRB_API void
mrb_gc_protect(mrb_state *mrb, mrb_value obj)
{
- if (mrb_special_const_p(obj)) return;
- gc_protect(mrb, mrb_basic_ptr(obj));
+ if (mrb_immediate_p(obj)) return;
+ gc_protect(mrb, &mrb->gc, mrb_basic_ptr(obj));
+}
+
+#define GC_ROOT_NAME "_gc_root_"
+
+/* mrb_gc_register() keeps the object from GC.
+
+ Register your object when it's exported to C world,
+ without reference from Ruby world, e.g. callback
+ arguments. Don't forget to remove the obejct using
+ mrb_gc_unregister, otherwise your object will leak.
+*/
+
+MRB_API void
+mrb_gc_register(mrb_state *mrb, mrb_value obj)
+{
+ mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
+ mrb_value table = mrb_gv_get(mrb, root);
+
+ if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) {
+ table = mrb_ary_new(mrb);
+ mrb_gv_set(mrb, root, table);
+ }
+ mrb_ary_push(mrb, table, obj);
+}
+
+/* mrb_gc_unregister() removes the object from GC root. */
+MRB_API void
+mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
+{
+ mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME);
+ mrb_value table = mrb_gv_get(mrb, root);
+ struct RArray *a;
+ mrb_int i, j;
+
+ if (mrb_nil_p(table)) return;
+ if (mrb_type(table) != MRB_TT_ARRAY) {
+ mrb_gv_set(mrb, root, mrb_nil_value());
+ return;
+ }
+ a = mrb_ary_ptr(table);
+ mrb_ary_modify(mrb, a);
+ for (i=j=0; i<a->len; i++) {
+ if (!mrb_obj_eq(mrb, a->ptr[i], obj)) {
+ a->ptr[j++] = a->ptr[i];
+ }
+ }
+ a->len = j;
}
-struct RBasic*
+MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{
struct RBasic *p;
static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
+ mrb_gc *gc = &mrb->gc;
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
#endif
- if (mrb->gc_threshold < mrb->live) {
+ if (gc->threshold < gc->live) {
mrb_incremental_gc(mrb);
}
- if (mrb->free_heaps == NULL) {
- add_heap(mrb);
+ if (gc->free_heaps == NULL) {
+ add_heap(mrb, gc);
}
- p = mrb->free_heaps->freelist;
- mrb->free_heaps->freelist = ((struct free_obj*)p)->next;
- if (mrb->free_heaps->freelist == NULL) {
- unlink_free_heap_page(mrb, mrb->free_heaps);
+ p = gc->free_heaps->freelist;
+ gc->free_heaps->freelist = ((struct free_obj*)p)->next;
+ if (gc->free_heaps->freelist == NULL) {
+ unlink_free_heap_page(gc, gc->free_heaps);
}
- mrb->live++;
- gc_protect(mrb, p);
+ gc->live++;
+ gc_protect(mrb, gc, p);
*(RVALUE *)p = RVALUE_zero;
p->tt = ttype;
p->c = cls;
- paint_partial_white(mrb, p);
+ paint_partial_white(gc, p);
return p;
}
static inline void
-add_gray_list(mrb_state *mrb, struct RBasic *obj)
+add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
#ifdef MRB_GC_STRESS
if (obj->tt > MRB_TT_MAXDEFINE) {
@@ -427,8 +510,8 @@ add_gray_list(mrb_state *mrb, struct RBasic *obj)
}
#endif
paint_gray(obj);
- obj->gcnext = mrb->gray_list;
- mrb->gray_list = obj;
+ obj->gcnext = gc->gray_list;
+ gc->gray_list = obj;
}
static void
@@ -485,15 +568,20 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
}
static void
-gc_mark_children(mrb_state *mrb, struct RBasic *obj)
+gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
mrb_assert(is_gray(obj));
paint_black(obj);
- mrb->gray_list = obj->gcnext;
+ gc->gray_list = obj->gcnext;
mrb_gc_mark(mrb, (struct RBasic*)obj->c);
switch (obj->tt) {
case MRB_TT_ICLASS:
- mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super);
+ {
+ struct RClass *c = (struct RClass*)obj;
+ if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN))
+ mrb_gc_mark_mt(mrb, c);
+ mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super);
+ }
break;
case MRB_TT_CLASS:
@@ -509,6 +597,7 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
case MRB_TT_OBJECT:
case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
mrb_gc_mark_iv(mrb, (struct RObject*)obj);
break;
@@ -526,9 +615,9 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
struct REnv *e = (struct REnv*)obj;
if (!MRB_ENV_STACK_SHARED_P(e)) {
- int i, len;
+ mrb_int i, len;
- len = (int)MRB_ENV_STACK_LEN(e);
+ len = MRB_ENV_STACK_LEN(e);
for (i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
}
@@ -579,13 +668,13 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
}
}
-void
+MRB_API void
mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
{
if (obj == 0) return;
if (!is_white(obj)) return;
mrb_assert((obj)->tt != MRB_TT_FREE);
- add_gray_list(mrb, obj);
+ add_gray_list(mrb, &mrb->gc, obj);
}
static void
@@ -608,6 +697,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
#endif
case MRB_TT_OBJECT:
+ case MRB_TT_EXCEPTION:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
break;
@@ -617,7 +707,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
mrb_gc_free_mt(mrb, (struct RClass*)obj);
mrb_gc_free_iv(mrb, (struct RObject*)obj);
break;
-
+ case MRB_TT_ICLASS:
+ if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN))
+ mrb_gc_free_mt(mrb, (struct RClass*)obj);
+ break;
case MRB_TT_ENV:
{
struct REnv *e = (struct REnv*)obj;
@@ -639,7 +732,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
break;
case MRB_TT_ARRAY:
- if (obj->flags & MRB_ARY_SHARED)
+ if (ARY_SHARED_P(obj))
mrb_ary_decref(mrb, ((struct RArray*)obj)->aux.shared);
else
mrb_free(mrb, ((struct RArray*)obj)->ptr);
@@ -685,19 +778,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
}
static void
-root_scan_phase(mrb_state *mrb)
+root_scan_phase(mrb_state *mrb, mrb_gc *gc)
{
size_t i, e;
- if (!is_minor_gc(mrb)) {
- mrb->gray_list = NULL;
- mrb->atomic_gray_list = NULL;
+ if (!is_minor_gc(gc)) {
+ gc->gray_list = NULL;
+ gc->atomic_gray_list = NULL;
}
mrb_gc_mark_gv(mrb);
/* mark arena */
- for (i=0,e=mrb->arena_idx; i<e; i++) {
- mrb_gc_mark(mrb, mrb->arena[i]);
+ for (i=0,e=gc->arena_idx; i<e; i++) {
+ mrb_gc_mark(mrb, gc->arena[i]);
}
/* mark class hierarchy */
mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
@@ -718,11 +811,11 @@ root_scan_phase(mrb_state *mrb)
}
static size_t
-gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
+gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
size_t children = 0;
- gc_mark_children(mrb, obj);
+ gc_mark_children(mrb, gc, obj);
switch (obj->tt) {
case MRB_TT_ICLASS:
@@ -743,6 +836,7 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
case MRB_TT_OBJECT:
case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
break;
@@ -800,68 +894,68 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
static void
-gc_mark_gray_list(mrb_state *mrb) {
- while (mrb->gray_list) {
- if (is_gray(mrb->gray_list))
- gc_mark_children(mrb, mrb->gray_list);
+gc_mark_gray_list(mrb_state *mrb, mrb_gc *gc) {
+ while (gc->gray_list) {
+ if (is_gray(gc->gray_list))
+ gc_mark_children(mrb, gc, gc->gray_list);
else
- mrb->gray_list = mrb->gray_list->gcnext;
+ gc->gray_list = gc->gray_list->gcnext;
}
}
static size_t
-incremental_marking_phase(mrb_state *mrb, size_t limit)
+incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
size_t tried_marks = 0;
- while (mrb->gray_list && tried_marks < limit) {
- tried_marks += gc_gray_mark(mrb, mrb->gray_list);
+ while (gc->gray_list && tried_marks < limit) {
+ tried_marks += gc_gray_mark(mrb, gc, gc->gray_list);
}
return tried_marks;
}
static void
-final_marking_phase(mrb_state *mrb)
+final_marking_phase(mrb_state *mrb, mrb_gc *gc)
{
mark_context_stack(mrb, mrb->root_c);
- gc_mark_gray_list(mrb);
- mrb_assert(mrb->gray_list == NULL);
- mrb->gray_list = mrb->atomic_gray_list;
- mrb->atomic_gray_list = NULL;
- gc_mark_gray_list(mrb);
- mrb_assert(mrb->gray_list == NULL);
+ gc_mark_gray_list(mrb, gc);
+ mrb_assert(gc->gray_list == NULL);
+ gc->gray_list = gc->atomic_gray_list;
+ gc->atomic_gray_list = NULL;
+ gc_mark_gray_list(mrb, gc);
+ mrb_assert(gc->gray_list == NULL);
}
static void
-prepare_incremental_sweep(mrb_state *mrb)
+prepare_incremental_sweep(mrb_state *mrb, mrb_gc *gc)
{
- mrb->gc_state = GC_STATE_SWEEP;
- mrb->sweeps = mrb->heaps;
- mrb->gc_live_after_mark = mrb->live;
+ gc->state = MRB_GC_STATE_SWEEP;
+ gc->sweeps = gc->heaps;
+ gc->live_after_mark = gc->live;
}
static size_t
-incremental_sweep_phase(mrb_state *mrb, size_t limit)
+incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
- struct heap_page *page = mrb->sweeps;
+ mrb_heap_page *page = gc->sweeps;
size_t tried_sweep = 0;
while (page && (tried_sweep < limit)) {
- RVALUE *p = page->objects;
+ RVALUE *p = objects(page);
RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
size_t freed = 0;
mrb_bool dead_slot = TRUE;
- int full = (page->freelist == NULL);
+ mrb_bool full = (page->freelist == NULL);
- if (is_minor_gc(mrb) && page->old) {
+ if (is_minor_gc(gc) && page->old) {
/* skip a slot which doesn't contain any young object */
p = e;
dead_slot = FALSE;
}
while (p<e) {
- if (is_dead(mrb, &p->as.basic)) {
+ if (is_dead(gc, &p->as.basic)) {
if (p->as.basic.tt != MRB_TT_FREE) {
obj_free(mrb, &p->as.basic);
p->as.free.next = page->freelist;
@@ -870,8 +964,8 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
}
}
else {
- if (!is_generational(mrb))
- paint_partial_white(mrb, &p->as.basic); /* next gc target */
+ if (!is_generational(gc))
+ paint_partial_white(gc, &p->as.basic); /* next gc target */
dead_slot = 0;
}
p++;
@@ -879,54 +973,54 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
/* free dead slot */
if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
- struct heap_page *next = page->next;
+ mrb_heap_page *next = page->next;
- unlink_heap_page(mrb, page);
- unlink_free_heap_page(mrb, page);
+ unlink_heap_page(gc, page);
+ unlink_free_heap_page(gc, page);
mrb_free(mrb, page);
page = next;
}
else {
if (full && freed > 0) {
- link_free_heap_page(mrb, page);
+ link_free_heap_page(gc, page);
}
- if (page->freelist == NULL && is_minor_gc(mrb))
+ if (page->freelist == NULL && is_minor_gc(gc))
page->old = TRUE;
else
page->old = FALSE;
page = page->next;
}
tried_sweep += MRB_HEAP_PAGE_SIZE;
- mrb->live -= freed;
- mrb->gc_live_after_mark -= freed;
+ gc->live -= freed;
+ gc->live_after_mark -= freed;
}
- mrb->sweeps = page;
+ gc->sweeps = page;
return tried_sweep;
}
static size_t
-incremental_gc(mrb_state *mrb, size_t limit)
+incremental_gc(mrb_state *mrb, mrb_gc *gc, size_t limit)
{
- switch (mrb->gc_state) {
- case GC_STATE_NONE:
- root_scan_phase(mrb);
- mrb->gc_state = GC_STATE_MARK;
- flip_white_part(mrb);
+ switch (gc->state) {
+ case MRB_GC_STATE_ROOT:
+ root_scan_phase(mrb, gc);
+ gc->state = MRB_GC_STATE_MARK;
+ flip_white_part(gc);
return 0;
- case GC_STATE_MARK:
- if (mrb->gray_list) {
- return incremental_marking_phase(mrb, limit);
+ case MRB_GC_STATE_MARK:
+ if (gc->gray_list) {
+ return incremental_marking_phase(mrb, gc, limit);
}
else {
- final_marking_phase(mrb);
- prepare_incremental_sweep(mrb);
+ final_marking_phase(mrb, gc);
+ prepare_incremental_sweep(mrb, gc);
return 0;
}
- case GC_STATE_SWEEP: {
+ case MRB_GC_STATE_SWEEP: {
size_t tried_sweep = 0;
- tried_sweep = incremental_sweep_phase(mrb, limit);
+ tried_sweep = incremental_sweep_phase(mrb, gc, limit);
if (tried_sweep == 0)
- mrb->gc_state = GC_STATE_NONE;
+ gc->state = MRB_GC_STATE_ROOT;
return tried_sweep;
}
default:
@@ -937,79 +1031,81 @@ incremental_gc(mrb_state *mrb, size_t limit)
}
static void
-incremental_gc_until(mrb_state *mrb, enum gc_state to_state)
+incremental_gc_until(mrb_state *mrb, mrb_gc *gc, mrb_gc_state to_state)
{
do {
- incremental_gc(mrb, ~0);
- } while (mrb->gc_state != to_state);
+ incremental_gc(mrb, gc, SIZE_MAX);
+ } while (gc->state != to_state);
}
static void
-incremental_gc_step(mrb_state *mrb)
+incremental_gc_step(mrb_state *mrb, mrb_gc *gc)
{
size_t limit = 0, result = 0;
- limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio;
+ limit = (GC_STEP_SIZE/100) * gc->step_ratio;
while (result < limit) {
- result += incremental_gc(mrb, limit);
- if (mrb->gc_state == GC_STATE_NONE)
+ result += incremental_gc(mrb, gc, limit);
+ if (gc->state == MRB_GC_STATE_ROOT)
break;
}
- mrb->gc_threshold = mrb->live + GC_STEP_SIZE;
+ gc->threshold = gc->live + GC_STEP_SIZE;
}
static void
-clear_all_old(mrb_state *mrb)
+clear_all_old(mrb_state *mrb, mrb_gc *gc)
{
- mrb_bool origin_mode = mrb->is_generational_gc_mode;
+ mrb_bool origin_mode = gc->generational;
- mrb_assert(is_generational(mrb));
- if (is_major_gc(mrb)) {
+ mrb_assert(is_generational(gc));
+ if (is_major_gc(gc)) {
/* finish the half baked GC */
- incremental_gc_until(mrb, GC_STATE_NONE);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
}
/* Sweep the dead objects, then reset all the live objects
* (including all the old objects, of course) to white. */
- mrb->is_generational_gc_mode = FALSE;
- prepare_incremental_sweep(mrb);
- incremental_gc_until(mrb, GC_STATE_NONE);
- mrb->is_generational_gc_mode = origin_mode;
+ gc->generational = FALSE;
+ prepare_incremental_sweep(mrb, gc);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->generational = origin_mode;
- /* The gray objects has already been painted as white */
- mrb->atomic_gray_list = mrb->gray_list = NULL;
+ /* The gray objects have already been painted as white */
+ gc->atomic_gray_list = gc->gray_list = NULL;
}
-void
+MRB_API void
mrb_incremental_gc(mrb_state *mrb)
{
- if (mrb->gc_disabled) return;
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled) return;
GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
GC_TIME_START;
- if (is_minor_gc(mrb)) {
- incremental_gc_until(mrb, GC_STATE_NONE);
+ if (is_minor_gc(gc)) {
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
}
else {
- incremental_gc_step(mrb);
+ incremental_gc_step(mrb, gc);
}
- if (mrb->gc_state == GC_STATE_NONE) {
- mrb_assert(mrb->live >= mrb->gc_live_after_mark);
- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
- if (mrb->gc_threshold < GC_STEP_SIZE) {
- mrb->gc_threshold = GC_STEP_SIZE;
+ if (gc->state == MRB_GC_STATE_ROOT) {
+ mrb_assert(gc->live >= gc->live_after_mark);
+ gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio;
+ if (gc->threshold < GC_STEP_SIZE) {
+ gc->threshold = GC_STEP_SIZE;
}
- if (is_major_gc(mrb)) {
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->gc_full = FALSE;
+ if (is_major_gc(gc)) {
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
}
- else if (is_minor_gc(mrb)) {
- if (mrb->live > mrb->majorgc_old_threshold) {
- clear_all_old(mrb);
- mrb->gc_full = TRUE;
+ else if (is_minor_gc(gc)) {
+ if (gc->live > gc->majorgc_old_threshold) {
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
}
}
}
@@ -1018,64 +1114,69 @@ mrb_incremental_gc(mrb_state *mrb)
}
/* Perform a full gc cycle */
-void
+MRB_API void
mrb_full_gc(mrb_state *mrb)
{
- if (mrb->gc_disabled) return;
+ mrb_gc *gc = &mrb->gc;
+
+ if (gc->disabled) return;
+
GC_INVOKE_TIME_REPORT("mrb_full_gc()");
GC_TIME_START;
- if (is_generational(mrb)) {
+ if (is_generational(gc)) {
/* clear all the old objects back to young */
- clear_all_old(mrb);
- mrb->gc_full = TRUE;
+ clear_all_old(mrb, gc);
+ gc->full = TRUE;
}
- else if (mrb->gc_state != GC_STATE_NONE) {
+ else if (gc->state != MRB_GC_STATE_ROOT) {
/* finish half baked GC cycle */
- incremental_gc_until(mrb, GC_STATE_NONE);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
}
- incremental_gc_until(mrb, GC_STATE_NONE);
- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio;
- if (is_generational(mrb)) {
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->gc_full = FALSE;
+ if (is_generational(gc)) {
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
}
GC_TIME_STOP_AND_REPORT;
}
-void
+MRB_API void
mrb_garbage_collect(mrb_state *mrb)
{
mrb_full_gc(mrb);
}
-int
+MRB_API int
mrb_gc_arena_save(mrb_state *mrb)
{
- return mrb->arena_idx;
+ return mrb->gc.arena_idx;
}
-void
+MRB_API void
mrb_gc_arena_restore(mrb_state *mrb, int idx)
{
+ mrb_gc *gc = &mrb->gc;
+
#ifndef MRB_GC_FIXED_ARENA
- int capa = mrb->arena_capa;
+ int capa = gc->arena_capa;
if (idx < capa / 2) {
capa = (int)(capa * 0.66);
if (capa < MRB_GC_ARENA_SIZE) {
capa = MRB_GC_ARENA_SIZE;
}
- if (capa != mrb->arena_capa) {
- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa);
- mrb->arena_capa = capa;
+ if (capa != gc->arena_capa) {
+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
+ gc->arena_capa = capa;
}
}
#endif
- mrb->arena_idx = idx;
+ gc->arena_idx = idx;
}
/*
@@ -1083,21 +1184,23 @@ mrb_gc_arena_restore(mrb_state *mrb, int idx)
* Paint obj(Black) -> value(White) to obj(Black) -> value(Gray).
*/
-void
+MRB_API void
mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value)
{
+ mrb_gc *gc = &mrb->gc;
+
if (!is_black(obj)) return;
if (!is_white(value)) return;
- mrb_assert(!is_dead(mrb, value) && !is_dead(mrb, obj));
- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE);
+ mrb_assert(gc->state == MRB_GC_STATE_MARK || (!is_dead(gc, value) && !is_dead(gc, obj)));
+ mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT);
- if (is_generational(mrb) || mrb->gc_state == GC_STATE_MARK) {
- add_gray_list(mrb, value);
+ if (is_generational(gc) || gc->state == MRB_GC_STATE_MARK) {
+ add_gray_list(mrb, gc, value);
}
else {
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
- paint_partial_white(mrb, obj); /* for never write barriers */
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
+ paint_partial_white(gc, obj); /* for never write barriers */
}
}
@@ -1110,16 +1213,18 @@ mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value
* e.g. Set element on Array.
*/
-void
+MRB_API void
mrb_write_barrier(mrb_state *mrb, struct RBasic *obj)
{
+ mrb_gc *gc = &mrb->gc;
+
if (!is_black(obj)) return;
- mrb_assert(!is_dead(mrb, obj));
- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE);
+ mrb_assert(!is_dead(gc, obj));
+ mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT);
paint_gray(obj);
- obj->gcnext = mrb->atomic_gray_list;
- mrb->atomic_gray_list = obj;
+ obj->gcnext = gc->atomic_gray_list;
+ gc->atomic_gray_list = obj;
}
/*
@@ -1153,9 +1258,9 @@ gc_start(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_enable(mrb_state *mrb, mrb_value obj)
{
- int old = mrb->gc_disabled;
+ mrb_bool old = mrb->gc.disabled;
- mrb->gc_disabled = FALSE;
+ mrb->gc.disabled = FALSE;
return mrb_bool_value(old);
}
@@ -1175,9 +1280,9 @@ gc_enable(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_disable(mrb_state *mrb, mrb_value obj)
{
- int old = mrb->gc_disabled;
+ mrb_bool old = mrb->gc.disabled;
- mrb->gc_disabled = TRUE;
+ mrb->gc.disabled = TRUE;
return mrb_bool_value(old);
}
@@ -1193,7 +1298,7 @@ gc_disable(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc_interval_ratio);
+ return mrb_fixnum_value(mrb->gc.interval_ratio);
}
/*
@@ -1211,7 +1316,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
mrb_int ratio;
mrb_get_args(mrb, "i", &ratio);
- mrb->gc_interval_ratio = ratio;
+ mrb->gc.interval_ratio = ratio;
return mrb_nil_value();
}
@@ -1226,7 +1331,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
static mrb_value
gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
{
- return mrb_fixnum_value(mrb->gc_step_ratio);
+ return mrb_fixnum_value(mrb->gc.step_ratio);
}
/*
@@ -1244,24 +1349,24 @@ gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
mrb_int ratio;
mrb_get_args(mrb, "i", &ratio);
- mrb->gc_step_ratio = ratio;
+ mrb->gc.step_ratio = ratio;
return mrb_nil_value();
}
static void
-change_gen_gc_mode(mrb_state *mrb, mrb_int enable)
+change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
{
- if (is_generational(mrb) && !enable) {
- clear_all_old(mrb);
- mrb_assert(mrb->gc_state == GC_STATE_NONE);
- mrb->gc_full = FALSE;
+ if (is_generational(gc) && !enable) {
+ clear_all_old(mrb, gc);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
+ gc->full = FALSE;
}
- else if (!is_generational(mrb) && enable) {
- incremental_gc_until(mrb, GC_STATE_NONE);
- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
- mrb->gc_full = FALSE;
+ else if (!is_generational(gc) && enable) {
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT);
+ gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
+ gc->full = FALSE;
}
- mrb->is_generational_gc_mode = enable;
+ gc->generational = enable;
}
/*
@@ -1275,7 +1380,7 @@ change_gen_gc_mode(mrb_state *mrb, mrb_int enable)
static mrb_value
gc_generational_mode_get(mrb_state *mrb, mrb_value self)
{
- return mrb_bool_value(mrb->is_generational_gc_mode);
+ return mrb_bool_value(mrb->gc.generational);
}
/*
@@ -1292,21 +1397,22 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
mrb_bool enable;
mrb_get_args(mrb, "b", &enable);
- if (mrb->is_generational_gc_mode != enable)
- change_gen_gc_mode(mrb, enable);
+ if (mrb->gc.generational != enable)
+ change_gen_gc_mode(mrb, &mrb->gc, enable);
return mrb_bool_value(enable);
}
-void
-mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
+
+static void
+gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
{
- struct heap_page* page = mrb->heaps;
+ mrb_heap_page* page = gc->heaps;
while (page != NULL) {
RVALUE *p, *pend;
- p = page->objects;
+ p = objects(page);
pend = p + MRB_HEAP_PAGE_SIZE;
for (;p < pend; p++) {
(*callback)(mrb, &p->as.basic, data);
@@ -1316,6 +1422,12 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo
}
}
+void
+mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
+{
+ gc_each_objects(mrb, &mrb->gc, callback, data);
+}
+
#ifdef GC_TEST
#ifdef GC_DEBUG
static mrb_value gc_test(mrb_state *, mrb_value);
@@ -1352,42 +1464,43 @@ test_mrb_field_write_barrier(void)
{
mrb_state *mrb = mrb_open();
struct RBasic *obj, *value;
+ mrb_gc *gc = &mrb->gc;
puts("test_mrb_field_write_barrier");
- mrb->is_generational_gc_mode = FALSE;
+ gc->generational = FALSE;
obj = mrb_basic_ptr(mrb_ary_new(mrb));
value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value"));
paint_black(obj);
- paint_partial_white(mrb,value);
+ paint_partial_white(gc, value);
- puts(" in GC_STATE_MARK");
- mrb->gc_state = GC_STATE_MARK;
+ puts(" in MRB_GC_STATE_MARK");
+ gc->state = MRB_GC_STATE_MARK;
mrb_field_write_barrier(mrb, obj, value);
mrb_assert(is_gray(value));
- puts(" in GC_STATE_SWEEP");
- paint_partial_white(mrb,value);
- mrb->gc_state = GC_STATE_SWEEP;
+ puts(" in MRB_GC_STATE_SWEEP");
+ paint_partial_white(gc, value);
+ gc->state = MRB_GC_STATE_SWEEP;
mrb_field_write_barrier(mrb, obj, value);
- mrb_assert(obj->color & mrb->current_white_part);
- mrb_assert(value->color & mrb->current_white_part);
+ mrb_assert(obj->color & gc->current_white_part);
+ mrb_assert(value->color & gc->current_white_part);
puts(" fail with black");
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
paint_white(obj);
- paint_partial_white(mrb,value);
+ paint_partial_white(gc, value);
mrb_field_write_barrier(mrb, obj, value);
- mrb_assert(obj->color & mrb->current_white_part);
+ mrb_assert(obj->color & gc->current_white_part);
puts(" fail with gray");
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
paint_black(obj);
paint_gray(value);
mrb_field_write_barrier(mrb, obj, value);
@@ -1400,9 +1513,9 @@ test_mrb_field_write_barrier(void)
obj = mrb_basic_ptr(mrb_ary_new(mrb));
mrb_value value = mrb_str_new_lit(mrb, "value");
paint_black(obj);
- paint_partial_white(mrb, mrb_basic_ptr(value));
+ paint_partial_white(gc, mrb_basic_ptr(value));
- mrb->gc_state = GC_STATE_MARK;
+ gc->state = MRB_GC_STATE_MARK;
mrb_field_write_barrier_value(mrb, obj, value);
mrb_assert(is_gray(mrb_basic_ptr(value)));
@@ -1416,17 +1529,18 @@ test_mrb_write_barrier(void)
{
mrb_state *mrb = mrb_open();
struct RBasic *obj;
+ mrb_gc *gc = &mrb->gc;
puts("test_mrb_write_barrier");
obj = mrb_basic_ptr(mrb_ary_new(mrb));
paint_black(obj);
- puts(" in GC_STATE_MARK");
- mrb->gc_state = GC_STATE_MARK;
+ puts(" in MRB_GC_STATE_MARK");
+ gc->state = MRB_GC_STATE_MARK;
mrb_write_barrier(mrb, obj);
mrb_assert(is_gray(obj));
- mrb_assert(mrb->atomic_gray_list == obj);
+ mrb_assert(gc->atomic_gray_list == obj);
puts(" fail with gray");
@@ -1443,19 +1557,20 @@ test_add_gray_list(void)
{
mrb_state *mrb = mrb_open();
struct RBasic *obj1, *obj2;
+ mrb_gc *gc = &mrb->gc;
puts("test_add_gray_list");
- change_gen_gc_mode(mrb, FALSE);
- mrb_assert(mrb->gray_list == NULL);
+ change_gen_gc_mode(mrb, gc, FALSE);
+ mrb_assert(gc->gray_list == NULL);
obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
- add_gray_list(mrb, obj1);
- mrb_assert(mrb->gray_list == obj1);
+ add_gray_list(mrb, gc, obj1);
+ mrb_assert(gc->gray_list == obj1);
mrb_assert(is_gray(obj1));
obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
- add_gray_list(mrb, obj2);
- mrb_assert(mrb->gray_list == obj2);
- mrb_assert(mrb->gray_list->gcnext == obj1);
+ add_gray_list(mrb, gc, obj2);
+ mrb_assert(gc->gray_list == obj2);
+ mrb_assert(gc->gray_list->gcnext == obj1);
mrb_assert(is_gray(obj2));
mrb_close(mrb);
@@ -1468,13 +1583,14 @@ test_gc_gray_mark(void)
mrb_value obj_v, value_v;
struct RBasic *obj;
size_t gray_num = 0;
+ mrb_gc *gc = &mrb->gc;
puts("test_gc_gray_mark");
puts(" in MRB_TT_CLASS");
obj = (struct RBasic*)mrb->object_class;
paint_gray(obj);
- gray_num = gc_gray_mark(mrb, obj);
+ gray_num = gc_gray_mark(mrb, gc, obj);
mrb_assert(is_black(obj));
mrb_assert(gray_num > 1);
@@ -1482,9 +1598,9 @@ test_gc_gray_mark(void)
obj_v = mrb_ary_new(mrb);
value_v = mrb_str_new_lit(mrb, "test");
paint_gray(mrb_basic_ptr(obj_v));
- paint_partial_white(mrb, mrb_basic_ptr(value_v));
+ paint_partial_white(gc, mrb_basic_ptr(value_v));
mrb_ary_push(mrb, obj_v, value_v);
- gray_num = gc_gray_mark(mrb, mrb_basic_ptr(obj_v));
+ gray_num = gc_gray_mark(mrb, gc, mrb_basic_ptr(obj_v));
mrb_assert(is_black(mrb_basic_ptr(obj_v)));
mrb_assert(is_gray(mrb_basic_ptr(value_v)));
mrb_assert(gray_num == 1);
@@ -1498,32 +1614,33 @@ test_incremental_gc(void)
mrb_state *mrb = mrb_open();
size_t max = ~0, live = 0, total = 0, freed = 0;
RVALUE *free;
- struct heap_page *page;
+ mrb_heap_page *page;
+ mrb_gc *gc = &mrb->gc;
puts("test_incremental_gc");
- change_gen_gc_mode(mrb, FALSE);
+ change_gen_gc_mode(mrb, gc, FALSE);
puts(" in mrb_full_gc");
mrb_full_gc(mrb);
- mrb_assert(mrb->gc_state == GC_STATE_NONE);
- puts(" in GC_STATE_NONE");
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_MARK);
- puts(" in GC_STATE_MARK");
- incremental_gc_until(mrb, GC_STATE_SWEEP);
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
+ puts(" in MRB_GC_STATE_ROOT");
+ incremental_gc(mrb, gc, max);
+ mrb_assert(gc->state == MRB_GC_STATE_MARK);
+ puts(" in MRB_GC_STATE_MARK");
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP);
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
- puts(" in GC_STATE_SWEEP");
- page = mrb->heaps;
+ puts(" in MRB_GC_STATE_SWEEP");
+ page = gc->heaps;
while (page) {
- RVALUE *p = page->objects;
+ RVALUE *p = objects(page);
RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
while (p<e) {
if (is_black(&p->as.basic)) {
live++;
}
- if (is_gray(&p->as.basic) && !is_dead(mrb, &p->as.basic)) {
+ if (is_gray(&p->as.basic) && !is_dead(gc, &p->as.basic)) {
printf("%p\n", &p->as.basic);
}
p++;
@@ -1532,44 +1649,44 @@ test_incremental_gc(void)
total += MRB_HEAP_PAGE_SIZE;
}
- mrb_assert(mrb->gray_list == NULL);
+ mrb_assert(gc->gray_list == NULL);
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
+ incremental_gc(mrb, gc, max);
+ mrb_assert(gc->state == MRB_GC_STATE_SWEEP);
- incremental_gc(mrb, max);
- mrb_assert(mrb->gc_state == GC_STATE_NONE);
+ incremental_gc(mrb, gc, max);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
- free = (RVALUE*)mrb->heaps->freelist;
+ free = (RVALUE*)gc->heaps->freelist;
while (free) {
freed++;
free = (RVALUE*)free->as.free.next;
}
- mrb_assert(mrb->live == live);
- mrb_assert(mrb->live == total-freed);
+ mrb_assert(gc->live == live);
+ mrb_assert(gc->live == total-freed);
puts("test_incremental_gc(gen)");
- incremental_gc_until(mrb, GC_STATE_SWEEP);
- change_gen_gc_mode(mrb, TRUE);
+ incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP);
+ change_gen_gc_mode(mrb, gc, TRUE);
- mrb_assert(mrb->gc_full == FALSE);
- mrb_assert(mrb->gc_state == GC_STATE_NONE);
+ mrb_assert(gc->full == FALSE);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
puts(" in minor");
- mrb_assert(is_minor_gc(mrb));
- mrb_assert(mrb->majorgc_old_threshold > 0);
- mrb->majorgc_old_threshold = 0;
+ mrb_assert(is_minor_gc(gc));
+ mrb_assert(gc->majorgc_old_threshold > 0);
+ gc->majorgc_old_threshold = 0;
mrb_incremental_gc(mrb);
- mrb_assert(mrb->gc_full == TRUE);
- mrb_assert(mrb->gc_state == GC_STATE_NONE);
+ mrb_assert(gc->full == TRUE);
+ mrb_assert(gc->state == MRB_GC_STATE_ROOT);
puts(" in major");
- mrb_assert(is_major_gc(mrb));
+ mrb_assert(is_major_gc(gc));
do {
mrb_incremental_gc(mrb);
- } while (mrb->gc_state != GC_STATE_NONE);
- mrb_assert(mrb->gc_full == FALSE);
+ } while (gc->state != MRB_GC_STATE_ROOT);
+ mrb_assert(gc->full == FALSE);
mrb_close(mrb);
}
@@ -1578,18 +1695,19 @@ void
test_incremental_sweep_phase(void)
{
mrb_state *mrb = mrb_open();
+ mrb_gc *gc = &mrb->gc;
puts("test_incremental_sweep_phase");
- add_heap(mrb);
- mrb->sweeps = mrb->heaps;
+ add_heap(mrb, gc);
+ gc->sweeps = gc->heaps;
- mrb_assert(mrb->heaps->next->next == NULL);
- mrb_assert(mrb->free_heaps->next->next == NULL);
- incremental_sweep_phase(mrb, MRB_HEAP_PAGE_SIZE*3);
+ mrb_assert(gc->heaps->next->next == NULL);
+ mrb_assert(gc->free_heaps->next->next == NULL);
+ incremental_sweep_phase(mrb, gc, MRB_HEAP_PAGE_SIZE * 3);
- mrb_assert(mrb->heaps->next == NULL);
- mrb_assert(mrb->heaps == mrb->free_heaps);
+ mrb_assert(gc->heaps->next == NULL);
+ mrb_assert(gc->heaps == gc->free_heaps);
mrb_close(mrb);
}
diff --git a/src/hash.c b/src/hash.c
index 1d449db3f..ac7256987 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -4,13 +4,13 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/hash.h"
-#include "mruby/khash.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/hash.h>
+#include <mruby/khash.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
/* a function to get hash value of a float number */
mrb_int mrb_float_id(mrb_float f);
@@ -36,20 +36,20 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
case MRB_TT_SYMBOL:
h = (khint_t)mrb_symbol(key);
- return kh_int_hash_func(mrb,h);
+ return kh_int_hash_func(mrb, h);
case MRB_TT_FIXNUM:
h = (khint_t)mrb_float_id((mrb_float)mrb_fixnum(key));
- return kh_int_hash_func(mrb,h);
+ return kh_int_hash_func(mrb, h);
case MRB_TT_FLOAT:
h = (khint_t)mrb_float_id(mrb_float(key));
- return kh_int_hash_func(mrb,h);
+ return kh_int_hash_func(mrb, h);
default:
hv = mrb_funcall(mrb, key, "hash", 0);
h = (khint_t)t ^ mrb_fixnum(hv);
- return kh_int_hash_func(mrb,h);
+ return kh_int_hash_func(mrb, h);
}
}
@@ -104,10 +104,11 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
static inline mrb_value
mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
{
- if (mrb_string_p(key))
- return mrb_str_dup(mrb, key);
- else
- return key;
+ if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) {
+ key = mrb_str_dup(mrb, key);
+ RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key));
+ }
+ return key;
}
#define KEY(key) mrb_hash_ht_key(mrb, key)
@@ -144,7 +145,7 @@ mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
}
-mrb_value
+MRB_API mrb_value
mrb_hash_new_capa(mrb_state *mrb, int capa)
{
struct RHash *h;
@@ -158,13 +159,13 @@ mrb_hash_new_capa(mrb_state *mrb, int capa)
return mrb_obj_value(h);
}
-mrb_value
+MRB_API mrb_value
mrb_hash_new(mrb_state *mrb)
{
return mrb_hash_new_capa(mrb, 0);
}
-mrb_value
+MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{
khash_t(ht) *h = RHASH_TBL(hash);
@@ -183,7 +184,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
return RHASH_IFNONE(hash);
}
-mrb_value
+MRB_API mrb_value
mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
{
khash_t(ht) *h = RHASH_TBL(hash);
@@ -199,7 +200,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
return def;
}
-void
+MRB_API void
mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
{
khash_t(ht) *h;
@@ -241,11 +242,11 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
ret_h = ret->ht;
for (k = kh_begin(h); k != kh_end(h); k++) {
- if (kh_exist(h,k)) {
+ if (kh_exist(h, k)) {
int ai = mrb_gc_arena_save(mrb);
- ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h,k)));
+ ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h, k)));
mrb_gc_arena_restore(mrb, ai);
- kh_val(ret_h, ret_k) = kh_val(h,k);
+ kh_val(ret_h, ret_k) = kh_val(h, k);
}
}
}
@@ -253,19 +254,19 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
return mrb_obj_value(ret);
}
-mrb_value
+MRB_API mrb_value
mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
{
return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash");
}
-khash_t(ht) *
+MRB_API khash_t(ht)*
mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
if (!h) {
- RHASH_TBL(hash) = kh_init(ht, mrb);
+ return RHASH_TBL(hash) = kh_init(ht, mrb);
}
return h;
}
@@ -293,22 +294,22 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash)
* default value. It is the block's responsibility to store the value
* in the hash if required.
*
- * h = Hash.new("Go Fish")
- * h["a"] = 100
- * h["b"] = 200
- * h["a"] #=> 100
- * h["c"] #=> "Go Fish"
- * # The following alters the single default object
- * h["c"].upcase! #=> "GO FISH"
- * h["d"] #=> "GO FISH"
- * h.keys #=> ["a", "b"]
- *
- * # While this creates a new default object each time
- * h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
- * h["c"] #=> "Go Fish: c"
- * h["c"].upcase! #=> "GO FISH: C"
- * h["d"] #=> "Go Fish: d"
- * h.keys #=> ["c", "d"]
+ * h = Hash.new("Go Fish")
+ * h["a"] = 100
+ * h["b"] = 200
+ * h["a"] #=> 100
+ * h["c"] #=> "Go Fish"
+ * # The following alters the single default object
+ * h["c"].upcase! #=> "GO FISH"
+ * h["d"] #=> "GO FISH"
+ * h.keys #=> ["a", "b"]
+ *
+ * # While this creates a new default object each time
+ * h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
+ * h["c"] #=> "Go Fish: c"
+ * h["c"].upcase! #=> "GO FISH: C"
+ * h["d"] #=> "Go Fish: d"
+ * h.keys #=> ["c", "d"]
*
*/
@@ -478,7 +479,7 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
return ifnone;
}
-mrb_value
+MRB_API mrb_value
mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
{
khash_t(ht) *h = RHASH_TBL(hash);
@@ -516,10 +517,10 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
* key is not found, pass in the key and return the result of
* <i>block</i>.
*
- * h = { "a" => 100, "b" => 200 }
- * h.delete("a") #=> 100
- * h.delete("z") #=> nil
- * h.delete("z") { |el| "#{el} not found" } #=> "z not found"
+ * h = { "a" => 100, "b" => 200 }
+ * h.delete("a") #=> 100
+ * h.delete("z") #=> nil
+ * h.delete("z") { |el| "#{el} not found" } #=> "z not found"
*
*/
static mrb_value
@@ -540,9 +541,9 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
* two-item array <code>[</code> <i>key, value</i> <code>]</code>, or
* the hash's default value if the hash is empty.
*
- * h = { 1 => "a", 2 => "b", 3 => "c" }
- * h.shift #=> [1, "a"]
- * h #=> {2=>"b", 3=>"c"}
+ * h = { 1 => "a", 2 => "b", 3 => "c" }
+ * h.shift #=> [1, "a"]
+ * h #=> {2=>"b", 3=>"c"}
*/
static mrb_value
@@ -553,18 +554,16 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
mrb_value delKey, delVal;
mrb_hash_modify(mrb, hash);
- if (h) {
- if (kh_size(h) > 0) {
- for (k = kh_begin(h); k != kh_end(h); k++) {
- if (!kh_exist(h,k)) continue;
+ if (h && kh_size(h) > 0) {
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (!kh_exist(h, k)) continue;
- delKey = kh_key(h,k);
- mrb_gc_protect(mrb, delKey);
- delVal = mrb_hash_delete_key(mrb, hash, delKey);
- mrb_gc_protect(mrb, delVal);
+ delKey = kh_key(h, k);
+ mrb_gc_protect(mrb, delKey);
+ delVal = mrb_hash_delete_key(mrb, hash, delKey);
+ mrb_gc_protect(mrb, delVal);
- return mrb_assoc_new(mrb, delKey, delVal);
- }
+ return mrb_assoc_new(mrb, delKey, delVal);
}
}
@@ -581,14 +580,14 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
* call-seq:
* hsh.clear -> hsh
*
- * Removes all key-value pairs from <i>hsh</i>.
+ * Removes all key-value pairs from `hsh`.
*
- * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
- * h.clear #=> {}
+ * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
+ * h.clear #=> {}
*
*/
-mrb_value
+MRB_API mrb_value
mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
@@ -610,10 +609,10 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
* use as a key (a <code>String</code> passed as a key will be
* duplicated and frozen).
*
- * h = { "a" => 100, "b" => 200 }
- * h["a"] = 9
- * h["c"] = 4
- * h #=> {"a"=>9, "b"=>200, "c"=>4}
+ * h = { "a" => 100, "b" => 200 }
+ * h["a"] = 9
+ * h["c"] = 4
+ * h #=> {"a"=>9, "b"=>200, "c"=>4}
*
*/
static mrb_value
@@ -659,7 +658,7 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
* {}.empty? #=> true
*
*/
-mrb_value
+MRB_API mrb_value
mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
{
khash_t(ht) *h = RHASH_TBL(self);
@@ -695,21 +694,22 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash)
*
*/
-mrb_value
+MRB_API mrb_value
mrb_hash_keys(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
- mrb_value ary, *p;
+ mrb_value ary;
+ mrb_value *p;
if (!h || kh_size(h) == 0) return mrb_ary_new(mrb);
ary = mrb_ary_new_capa(mrb, kh_size(h));
mrb_ary_set(mrb, ary, kh_size(h)-1, mrb_nil_value());
- p = RARRAY_PTR(ary);
+ p = mrb_ary_ptr(ary)->ptr;
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
- mrb_value kv = kh_key(h,k);
- mrb_hash_value hv = kh_value(h,k);
+ mrb_value kv = kh_key(h, k);
+ mrb_hash_value hv = kh_value(h, k);
p[hv.n] = kv;
}
@@ -741,7 +741,7 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
ary = mrb_ary_new_capa(mrb, kh_size(h));
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
- mrb_hash_value hv = kh_value(h,k);
+ mrb_hash_value hv = kh_value(h, k);
mrb_ary_set(mrb, ary, hv.n, hv.v);
}
@@ -814,7 +814,7 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
for (k = kh_begin(h); k != kh_end(h); k++) {
if (!kh_exist(h, k)) continue;
- if (mrb_equal(mrb, kh_value(h,k).v, val)) {
+ if (mrb_equal(mrb, kh_value(h, k).v, val)) {
return mrb_true_value();
}
}
@@ -827,7 +827,7 @@ mrb_init_hash(mrb_state *mrb)
{
struct RClass *h;
- h = mrb->hash_class = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
+ mrb->hash_class = h = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
MRB_SET_INSTANCE_TT(h, MRB_TT_HASH);
mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */
diff --git a/src/init.c b/src/init.c
index 9489cea10..9a6496df1 100644
--- a/src/init.c
+++ b/src/init.c
@@ -4,7 +4,7 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
+#include <mruby.h>
void mrb_init_symtbl(mrb_state*);
void mrb_init_class(mrb_state*);
@@ -24,8 +24,6 @@ void mrb_init_gc(mrb_state*);
void mrb_init_math(mrb_state*);
void mrb_init_version(mrb_state*);
void mrb_init_mrblib(mrb_state*);
-void mrb_init_mrbgems(mrb_state*);
-void mrb_final_mrbgems(mrb_state*);
#define DONE mrb_gc_arena_restore(mrb, 0);
void
@@ -50,7 +48,4 @@ mrb_init_core(mrb_state *mrb)
mrb_init_gc(mrb); DONE;
mrb_init_version(mrb); DONE;
mrb_init_mrblib(mrb); DONE;
-#ifndef DISABLE_GEMS
- mrb_init_mrbgems(mrb); DONE;
-#endif
}
diff --git a/src/kernel.c b/src/kernel.c
index 0258e5c15..af6a49be1 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -4,13 +4,13 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/error.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
typedef enum {
NOEX_PUBLIC = 0x00,
@@ -30,7 +30,7 @@ static mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s"));
- if (me && MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
+ if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
return TRUE;
return FALSE;
}
@@ -49,7 +49,7 @@ mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
* [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
* Time.new.inspect #=> "2008-03-08 19:43:39 +0900"
*/
-mrb_value
+MRB_API mrb_value
mrb_obj_inspect(mrb_state *mrb, mrb_value obj)
{
if ((mrb_type(obj) == MRB_TT_OBJECT) && mrb_obj_basic_to_s_p(mrb, obj)) {
@@ -186,16 +186,26 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
}
else {
/* block_given? called within block; check upper scope */
- if (ci->proc->env && ci->proc->env->stack) {
- given_p = !(ci->proc->env->stack == mrb->c->stbase ||
- mrb_nil_p(ci->proc->env->stack[1]));
- }
- else {
- if (ci->argc > 0) {
- bp += ci->argc;
+ if (ci->proc->env) {
+ struct REnv *e = ci->proc->env;
+ mrb_value *sp;
+
+ while (e->c) {
+ e = (struct REnv*)e->c;
+ }
+ sp = e->stack;
+ if (sp) {
+ /* top-level does not have block slot (alway false) */
+ if (sp == mrb->c->stbase)
+ return mrb_false_value();
+ ci = mrb->c->cibase + e->cioff;
+ bp = ci[1].stackent + 1;
}
- given_p = !mrb_nil_p(*bp);
}
+ if (ci->argc > 0) {
+ bp += ci->argc;
+ }
+ given_p = !mrb_nil_p(*bp);
}
return mrb_bool_value(given_p);
@@ -230,14 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
/* copy singleton(unnamed) class */
struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class);
- if ((mrb_type(obj) == MRB_TT_CLASS) ||
- (mrb_type(obj) == MRB_TT_SCLASS)) { /* BUILTIN_TYPE(obj) == T_CLASS */
+ if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) {
clone->c = clone;
}
else {
clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass));
}
-
clone->super = klass->super;
if (klass->iv) {
mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass));
@@ -259,6 +267,21 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
{
struct RClass *dc = mrb_class_ptr(dst);
struct RClass *sc = mrb_class_ptr(src);
+ /* if the origin is not the same as the class, then the origin and
+ the current class need to be copied */
+ if (sc->flags & MRB_FLAG_IS_PREPENDED) {
+ struct RClass *c0 = sc->super;
+ struct RClass *c1 = dc;
+
+ /* copy prepended iclasses */
+ while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) {
+ c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0)));
+ c1 = c1->super;
+ c0 = c0->super;
+ }
+ c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0)));
+ c1->super->flags |= MRB_FLAG_IS_ORIGIN;
+ }
dc->mt = kh_copy(mt, mrb, sc->mt);
dc->super = sc->super;
}
@@ -275,6 +298,7 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
case MRB_TT_SCLASS:
case MRB_TT_HASH:
case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
mrb_iv_copy(mrb, dest, obj);
break;
@@ -310,15 +334,18 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj)
*
* Some Class(True False Nil Symbol Fixnum Float) Object cannot clone.
*/
-mrb_value
+MRB_API mrb_value
mrb_obj_clone(mrb_state *mrb, mrb_value self)
{
struct RObject *p;
mrb_value clone;
- if (mrb_special_const_p(self)) {
+ if (mrb_immediate_p(self)) {
mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self);
}
+ if (mrb_type(self) == MRB_TT_SCLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class");
+ }
p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self));
p->c = mrb_singleton_class_clone(mrb, self);
clone = mrb_obj_value(p);
@@ -346,15 +373,18 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self)
* the class.
*/
-mrb_value
+MRB_API mrb_value
mrb_obj_dup(mrb_state *mrb, mrb_value obj)
{
struct RBasic *p;
mrb_value dup;
- if (mrb_special_const_p(obj)) {
+ if (mrb_immediate_p(obj)) {
mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj);
}
+ if (mrb_type(obj) == MRB_TT_SCLASS) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class");
+ }
p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj));
dup = mrb_obj_value(p);
init_copy(mrb, dup, obj);
@@ -426,7 +456,7 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
* <code>Hash</code>. Any hash value that exceeds the capacity of a
* <code>Fixnum</code> will be truncated before being used.
*/
-mrb_value
+MRB_API mrb_value
mrb_obj_hash(mrb_state *mrb, mrb_value self)
{
return mrb_fixnum_value(mrb_obj_id(self));
@@ -450,7 +480,7 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self)
/* implementation of instance_eval */
mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
-mrb_bool
+MRB_API mrb_bool
mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c)
{
if (mrb_obj_class(mrb, obj) == c) return TRUE;
@@ -469,51 +499,10 @@ static mrb_value
obj_is_instance_of(mrb_state *mrb, mrb_value self)
{
mrb_value arg;
- mrb_bool instance_of_p;
mrb_get_args(mrb, "C", &arg);
- instance_of_p = mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg));
- return mrb_bool_value(instance_of_p);
-}
-
-static void
-valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, mrb_int len)
-{
- if (len < 2 || !(s[0] == '@' && s[1] != '@')) {
- mrb_name_error(mrb, iv_name_id, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name_id));
- }
-}
-
-static void
-check_iv_name(mrb_state *mrb, mrb_sym iv_name_id)
-{
- const char *s;
- mrb_int len;
-
- s = mrb_sym2name_len(mrb, iv_name_id, &len);
- valid_iv_name(mrb, iv_name_id, s, len);
-}
-
-static mrb_sym
-get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name)
-{
- mrb_sym iv_name_id;
-
- mrb_assert(mrb_symbol_p(iv_name) || mrb_string_p(iv_name));
-
- if (mrb_string_p(iv_name)) {
- char *p = RSTRING_PTR(iv_name);
- mrb_int l = RSTRING_LEN(iv_name);
- iv_name_id = mrb_intern(mrb, p, l);
- valid_iv_name(mrb, iv_name_id, p, l);
- }
- else {
- iv_name_id = mrb_symbol(iv_name);
- check_iv_name(mrb, iv_name_id);
- }
-
- return iv_name_id;
+ return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg)));
}
/* 15.3.1.3.20 */
@@ -537,15 +526,11 @@ get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name)
static mrb_value
mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self)
{
- mrb_sym mid;
- mrb_value sym;
- mrb_bool defined_p;
-
- mrb_get_args(mrb, "o", &sym);
- mid = get_valid_iv_sym(mrb, sym);
- defined_p = mrb_obj_iv_defined(mrb, mrb_obj_ptr(self), mid);
+ mrb_sym sym;
- return mrb_bool_value(defined_p);
+ mrb_get_args(mrb, "n", &sym);
+ mrb_iv_check(mrb, sym);
+ return mrb_bool_value(mrb_iv_defined(mrb, self, sym));
}
/* 15.3.1.3.21 */
@@ -571,13 +556,11 @@ mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_ivar_get(mrb_state *mrb, mrb_value self)
{
- mrb_sym iv_name_id;
- mrb_value iv_name;
-
- mrb_get_args(mrb, "o", &iv_name);
+ mrb_sym iv_name;
- iv_name_id = get_valid_iv_sym(mrb, iv_name);
- return mrb_iv_get(mrb, self, iv_name_id);
+ mrb_get_args(mrb, "n", &iv_name);
+ mrb_iv_check(mrb, iv_name);
+ return mrb_iv_get(mrb, self, iv_name);
}
/* 15.3.1.3.22 */
@@ -603,13 +586,12 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_obj_ivar_set(mrb_state *mrb, mrb_value self)
{
- mrb_sym iv_name_id;
- mrb_value iv_name, val;
-
- mrb_get_args(mrb, "oo", &iv_name, &val);
+ mrb_sym iv_name;
+ mrb_value val;
- iv_name_id = get_valid_iv_sym(mrb, iv_name);
- mrb_iv_set(mrb, self, iv_name_id, val);
+ mrb_get_args(mrb, "no", &iv_name, &val);
+ mrb_iv_check(mrb, iv_name);
+ mrb_iv_set(mrb, self, iv_name, val);
return val;
}
@@ -644,12 +626,10 @@ static mrb_value
mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
{
mrb_value arg;
- mrb_bool kind_of_p;
mrb_get_args(mrb, "C", &arg);
- kind_of_p = mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg));
- return mrb_bool_value(kind_of_p);
+ return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg)));
}
KHASH_DECLARE(st, mrb_sym, char, FALSE)
@@ -663,8 +643,8 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
khash_t(mt) *h = klass->mt;
if (!h) return;
for (i=0;i<kh_end(h);i++) {
- if (kh_exist(h, i)) {
- kh_put(st, mrb, set, kh_key(h,i));
+ if (kh_exist(h, i) && kh_value(h, i)) {
+ kh_put(st, mrb, set, kh_key(h, i));
}
}
}
@@ -674,13 +654,19 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
{
khint_t i;
mrb_value ary;
+ mrb_bool prepended = FALSE;
struct RClass* oldklass;
khash_t(st)* set = kh_init(st, mrb);
+ if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) {
+ MRB_CLASS_ORIGIN(klass);
+ prepended = TRUE;
+ }
+
oldklass = 0;
while (klass && (klass != oldklass)) {
method_entry_loop(mrb, klass, set);
- if ((klass->tt == MRB_TT_ICLASS) ||
+ if ((klass->tt == MRB_TT_ICLASS && !prepended) ||
(klass->tt == MRB_TT_SCLASS)) {
}
else {
@@ -693,7 +679,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
ary = mrb_ary_new(mrb);
for (i=0;i<kh_end(set);i++) {
if (kh_exist(set, i)) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
}
}
kh_destroy(st, mrb, set);
@@ -725,7 +711,7 @@ mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
ary = mrb_ary_new(mrb);
for (i=0;i<kh_end(set);i++) {
if (kh_exist(set, i)) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
}
}
kh_destroy(st, mrb, set);
@@ -737,9 +723,8 @@ static mrb_value
mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag)
{
if (recur)
- return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
- else
- return mrb_obj_singleton_methods(mrb, recur, obj);
+ return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
+ return mrb_obj_singleton_methods(mrb, recur, obj);
}
/* 15.3.1.3.31 */
/*
@@ -854,7 +839,7 @@ mrb_obj_public_methods(mrb_state *mrb, mrb_value self)
* raise "Failed to create socket"
* raise ArgumentError, "No parameters", caller
*/
-mrb_value
+MRB_API mrb_value
mrb_f_raise(mrb_state *mrb, mrb_value self)
{
mrb_value a[2], exc;
@@ -911,7 +896,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
mrb_value val;
mrb_get_args(mrb, "n", &sym);
- check_iv_name(mrb, sym);
+ mrb_iv_check(mrb, sym);
val = mrb_iv_remove(mrb, self, sym);
if (mrb_undef_p(val)) {
mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym));
@@ -1112,7 +1097,7 @@ mrb_init_kernel(mrb_state *mrb)
{
struct RClass *krn;
- krn = mrb->kernel_module = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */
+ mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */
mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */
mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */
mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */
diff --git a/src/keywords b/src/keywords
deleted file mode 100644
index 9cb86608c..000000000
--- a/src/keywords
+++ /dev/null
@@ -1,50 +0,0 @@
-%{
-struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
-%}
-
-struct kwtable;
-%%
-__ENCODING__, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END
-__FILE__, {keyword__FILE__, keyword__FILE__}, EXPR_END
-__LINE__, {keyword__LINE__, keyword__LINE__}, EXPR_END
-BEGIN, {keyword_BEGIN, keyword_BEGIN}, EXPR_END
-END, {keyword_END, keyword_END}, EXPR_END
-alias, {keyword_alias, keyword_alias}, EXPR_FNAME
-and, {keyword_and, keyword_and}, EXPR_VALUE
-begin, {keyword_begin, keyword_begin}, EXPR_BEG
-break, {keyword_break, keyword_break}, EXPR_MID
-case, {keyword_case, keyword_case}, EXPR_VALUE
-class, {keyword_class, keyword_class}, EXPR_CLASS
-def, {keyword_def, keyword_def}, EXPR_FNAME
-do, {keyword_do, keyword_do}, EXPR_BEG
-else, {keyword_else, keyword_else}, EXPR_BEG
-elsif, {keyword_elsif, keyword_elsif}, EXPR_VALUE
-end, {keyword_end, keyword_end}, EXPR_END
-ensure, {keyword_ensure, keyword_ensure}, EXPR_BEG
-false, {keyword_false, keyword_false}, EXPR_END
-for, {keyword_for, keyword_for}, EXPR_VALUE
-if, {keyword_if, modifier_if}, EXPR_VALUE
-in, {keyword_in, keyword_in}, EXPR_VALUE
-module, {keyword_module, keyword_module}, EXPR_VALUE
-next, {keyword_next, keyword_next}, EXPR_MID
-nil, {keyword_nil, keyword_nil}, EXPR_END
-not, {keyword_not, keyword_not}, EXPR_ARG
-or, {keyword_or, keyword_or}, EXPR_VALUE
-redo, {keyword_redo, keyword_redo}, EXPR_END
-rescue, {keyword_rescue, modifier_rescue}, EXPR_MID
-retry, {keyword_retry, keyword_retry}, EXPR_END
-return, {keyword_return, keyword_return}, EXPR_MID
-self, {keyword_self, keyword_self}, EXPR_END
-super, {keyword_super, keyword_super}, EXPR_ARG
-then, {keyword_then, keyword_then}, EXPR_BEG
-true, {keyword_true, keyword_true}, EXPR_END
-undef, {keyword_undef, keyword_undef}, EXPR_FNAME
-unless, {keyword_unless, modifier_unless}, EXPR_VALUE
-until, {keyword_until, modifier_until}, EXPR_VALUE
-when, {keyword_when, keyword_when}, EXPR_VALUE
-while, {keyword_while, modifier_while}, EXPR_VALUE
-yield, {keyword_yield, keyword_yield}, EXPR_ARG
-%%
diff --git a/src/lex.def b/src/lex.def
deleted file mode 100644
index ea456a843..000000000
--- a/src/lex.def
+++ /dev/null
@@ -1,212 +0,0 @@
-/* ANSI-C code produced by gperf version 3.0.3 */
-/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' src/keywords */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <[email protected]>."
-#endif
-
-#line 1 "src/keywords"
-
-struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
-#line 8 "src/keywords"
-struct kwtable;
-
-#define TOTAL_KEYWORDS 40
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 12
-#define MIN_HASH_VALUE 8
-#define MAX_HASH_VALUE 50
-/* maximum key range = 43, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-hash (register const char *str, register unsigned int len)
-{
- static const unsigned char asso_values[] =
- {
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 14, 51, 16, 8,
- 11, 13, 51, 51, 51, 51, 10, 51, 13, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 11, 51, 13, 1, 26,
- 4, 1, 8, 28, 51, 23, 51, 1, 1, 27,
- 5, 19, 21, 51, 8, 3, 3, 11, 51, 21,
- 24, 16, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51
- };
- register int hval = len;
-
- switch (hval)
- {
- default:
- hval += asso_values[(unsigned char)str[2]];
- /*FALLTHROUGH*/
- case 2:
- case 1:
- hval += asso_values[(unsigned char)str[0]];
- break;
- }
- return hval + asso_values[(unsigned char)str[len - 1]];
-}
-
-#ifdef __GNUC__
-__inline
-#ifdef __GNUC_STDC_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
-const struct kwtable *
-mrb_reserved_word (register const char *str, register unsigned int len)
-{
- static const struct kwtable wordlist[] =
- {
- {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 18 "src/keywords"
- {"break", {keyword_break, keyword_break}, EXPR_MID},
-#line 23 "src/keywords"
- {"else", {keyword_else, keyword_else}, EXPR_BEG},
-#line 33 "src/keywords"
- {"nil", {keyword_nil, keyword_nil}, EXPR_END},
-#line 26 "src/keywords"
- {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG},
-#line 25 "src/keywords"
- {"end", {keyword_end, keyword_end}, EXPR_END},
-#line 42 "src/keywords"
- {"then", {keyword_then, keyword_then}, EXPR_BEG},
-#line 34 "src/keywords"
- {"not", {keyword_not, keyword_not}, EXPR_ARG},
-#line 27 "src/keywords"
- {"false", {keyword_false, keyword_false}, EXPR_END},
-#line 40 "src/keywords"
- {"self", {keyword_self, keyword_self}, EXPR_END},
-#line 24 "src/keywords"
- {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE},
-#line 37 "src/keywords"
- {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID},
-#line 43 "src/keywords"
- {"true", {keyword_true, keyword_true}, EXPR_END},
-#line 46 "src/keywords"
- {"until", {keyword_until, modifier_until}, EXPR_VALUE},
-#line 45 "src/keywords"
- {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE},
-#line 39 "src/keywords"
- {"return", {keyword_return, keyword_return}, EXPR_MID},
-#line 21 "src/keywords"
- {"def", {keyword_def, keyword_def}, EXPR_FNAME},
-#line 16 "src/keywords"
- {"and", {keyword_and, keyword_and}, EXPR_VALUE},
-#line 22 "src/keywords"
- {"do", {keyword_do, keyword_do}, EXPR_BEG},
-#line 49 "src/keywords"
- {"yield", {keyword_yield, keyword_yield}, EXPR_ARG},
-#line 28 "src/keywords"
- {"for", {keyword_for, keyword_for}, EXPR_VALUE},
-#line 44 "src/keywords"
- {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME},
-#line 35 "src/keywords"
- {"or", {keyword_or, keyword_or}, EXPR_VALUE},
-#line 30 "src/keywords"
- {"in", {keyword_in, keyword_in}, EXPR_VALUE},
-#line 47 "src/keywords"
- {"when", {keyword_when, keyword_when}, EXPR_VALUE},
-#line 38 "src/keywords"
- {"retry", {keyword_retry, keyword_retry}, EXPR_END},
-#line 29 "src/keywords"
- {"if", {keyword_if, modifier_if}, EXPR_VALUE},
-#line 19 "src/keywords"
- {"case", {keyword_case, keyword_case}, EXPR_VALUE},
-#line 36 "src/keywords"
- {"redo", {keyword_redo, keyword_redo}, EXPR_END},
-#line 32 "src/keywords"
- {"next", {keyword_next, keyword_next}, EXPR_MID},
-#line 41 "src/keywords"
- {"super", {keyword_super, keyword_super}, EXPR_ARG},
-#line 31 "src/keywords"
- {"module", {keyword_module, keyword_module}, EXPR_VALUE},
-#line 17 "src/keywords"
- {"begin", {keyword_begin, keyword_begin}, EXPR_BEG},
-#line 12 "src/keywords"
- {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END},
-#line 11 "src/keywords"
- {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END},
-#line 10 "src/keywords"
- {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
-#line 14 "src/keywords"
- {"END", {keyword_END, keyword_END}, EXPR_END},
-#line 15 "src/keywords"
- {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME},
-#line 13 "src/keywords"
- {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
- {""},
-#line 20 "src/keywords"
- {"class", {keyword_class, keyword_class}, EXPR_CLASS},
- {""}, {""},
-#line 48 "src/keywords"
- {"while", {keyword_while, modifier_while}, EXPR_VALUE}
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = hash (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register const char *s = wordlist[key].name;
-
- if (*str == *s && !strcmp (str + 1, s + 1))
- return &wordlist[key];
- }
- }
- return 0;
-}
-#line 50 "src/keywords"
-
diff --git a/src/load.c b/src/load.c
index 8dea4a391..da88f0d3a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -7,28 +7,31 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include "mruby/dump.h"
-#include "mruby/irep.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
-#include "mruby/debug.h"
-#include "mruby/error.h"
-
-#if !defined(_WIN32) && SIZE_MAX < UINT32_MAX
-# define SIZE_ERROR_MUL(x, y) ((x) > SIZE_MAX / (y))
-# define SIZE_ERROR(x) ((x) > SIZE_MAX)
-#else
-# define SIZE_ERROR_MUL(x, y) (0)
-# define SIZE_ERROR(x) (0)
+#include <mruby/dump.h>
+#include <mruby/irep.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/debug.h>
+#include <mruby/error.h>
+
+#if SIZE_MAX < UINT32_MAX
+# error size_t must be at least 32 bits wide
#endif
-#if CHAR_BIT != 8
-# error This code assumes CHAR_BIT == 8
-#endif
+#define FLAG_BYTEORDER_BIG 2
+#define FLAG_BYTEORDER_LIL 4
+#define FLAG_BYTEORDER_NATIVE 8
+#define FLAG_SRC_MALLOC 1
+#define FLAG_SRC_STATIC 0
-#if UINT32_MAX > SIZE_MAX
-# error This code cannot be built on your environment.
-#endif
+#define SIZE_ERROR_MUL(nmemb, size) ((nmemb) > SIZE_MAX / (size))
+
+static size_t
+skip_padding(const uint8_t *buf)
+{
+ const size_t align = MRB_DUMP_ALIGNMENT;
+ return -(intptr_t)buf & (align-1);
+}
static size_t
offset_crc_body(void)
@@ -38,7 +41,7 @@ offset_crc_body(void)
}
static mrb_irep*
-read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
+read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
{
size_t i;
const uint8_t *src = bin;
@@ -67,14 +70,36 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
/* ISEQ BLOCK */
irep->ilen = (size_t)bin_to_uint32(src);
src += sizeof(uint32_t);
+ src += skip_padding(src);
+
if (irep->ilen > 0) {
- if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) {
+ if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
return NULL;
}
- irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen);
- for (i = 0; i < irep->ilen; i++) {
- irep->iseq[i] = (size_t)bin_to_uint32(src); /* iseq */
- src += sizeof(uint32_t);
+ if ((flags & FLAG_SRC_MALLOC) == 0 &&
+ (flags & FLAG_BYTEORDER_NATIVE)) {
+ irep->iseq = (mrb_code*)src;
+ src += sizeof(uint32_t) * irep->ilen;
+ irep->flags |= MRB_ISEQ_NO_FREE;
+ }
+ else {
+ irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen);
+ if (flags & FLAG_BYTEORDER_NATIVE) {
+ memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen);
+ src += sizeof(uint32_t) * irep->ilen;
+ }
+ else if (flags & FLAG_BYTEORDER_BIG) {
+ for (i = 0; i < irep->ilen; i++) {
+ irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */
+ src += sizeof(uint32_t);
+ }
+ }
+ else {
+ for (i = 0; i < irep->ilen; i++) {
+ irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */
+ src += sizeof(uint32_t);
+ }
+ }
}
}
@@ -82,7 +107,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
plen = (size_t)bin_to_uint32(src); /* number of pool */
src += sizeof(uint32_t);
if (plen > 0) {
- if (SIZE_ERROR_MUL(sizeof(mrb_value), plen)) {
+ if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
return NULL;
}
irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen);
@@ -93,7 +118,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
tt = *src++; /* pool TT */
pool_data_len = bin_to_uint16(src); /* pool data length */
src += sizeof(uint16_t);
- if (alloc) {
+ if (flags & FLAG_SRC_MALLOC) {
s = mrb_str_new(mrb, (char *)src, pool_data_len);
}
else {
@@ -127,7 +152,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
irep->slen = (size_t)bin_to_uint32(src); /* syms length */
src += sizeof(uint32_t);
if (irep->slen > 0) {
- if (SIZE_ERROR_MUL(sizeof(mrb_sym), irep->slen)) {
+ if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
return NULL;
}
irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
@@ -141,7 +166,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
continue;
}
- if (alloc) {
+ if (flags & FLAG_SRC_MALLOC) {
irep->syms[i] = mrb_intern(mrb, (char *)src, snl);
}
else {
@@ -163,16 +188,23 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool all
}
static mrb_irep*
-read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc)
+read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
{
- mrb_irep *irep = read_irep_record_1(mrb, bin, len, alloc);
+ mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags);
size_t i;
+ if (irep == NULL) {
+ return NULL;
+ }
+
bin += *len;
for (i=0; i<irep->rlen; i++) {
size_t rlen;
- irep->reps[i] = read_irep_record(mrb, bin, &rlen, alloc);
+ irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags);
+ if (irep->reps[i] == NULL) {
+ return NULL;
+ }
bin += rlen;
*len += rlen;
}
@@ -180,12 +212,12 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, mrb_bool alloc
}
static mrb_irep*
-read_section_irep(mrb_state *mrb, const uint8_t *bin, mrb_bool alloc)
+read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
{
size_t len;
bin += sizeof(struct rite_section_irep_header);
- return read_irep_record(mrb, bin, &len, alloc);
+ return read_irep_record(mrb, bin, &len, flags);
}
static int
@@ -201,9 +233,6 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t
fname_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
*len += sizeof(uint16_t);
- if (SIZE_ERROR(fname_len + 1)) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
fname = (char *)mrb_malloc(mrb, fname_len + 1);
memcpy(fname, bin, fname_len);
fname[fname_len] = '\0';
@@ -341,7 +370,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
size_t len;
int ret;
- ret =read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
+ ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
if (ret != MRB_DUMP_OK) return ret;
bin += len;
}
@@ -354,7 +383,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
}
static int
-read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc)
+read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
{
const uint8_t *bin;
ptrdiff_t diff;
@@ -375,7 +404,7 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_boo
for (i = 0; i < filenames_len; ++i) {
uint16_t f_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
- if (alloc) {
+ if (flags & FLAG_SRC_MALLOC) {
filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
}
else {
@@ -443,7 +472,7 @@ read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *rec
}
static int
-read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool alloc)
+read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
{
const uint8_t *bin;
ptrdiff_t diff;
@@ -453,7 +482,8 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, mrb_bool a
int result;
uint32_t syms_len;
mrb_sym *syms;
- mrb_sym (*intern_func)(mrb_state*, const char*, size_t) = alloc? mrb_intern : mrb_intern_static;
+ mrb_sym (*intern_func)(mrb_state*, const char*, size_t) =
+ (flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static;
bin = start;
header = (struct rite_section_lv_header const*)bin;
@@ -486,28 +516,36 @@ lv_exit:
}
static int
-read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
+read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags)
{
const struct rite_binary_header *header = (const struct rite_binary_header *)bin;
- if (memcmp(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)) != 0) {
- return MRB_DUMP_INVALID_FILE_HEADER;
+ if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) {
+ if (bigendian_p())
+ *flags |= FLAG_BYTEORDER_NATIVE;
+ else
+ *flags |= FLAG_BYTEORDER_BIG;
}
-
- if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) {
+ else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) {
+ if (bigendian_p())
+ *flags |= FLAG_BYTEORDER_LIL;
+ else
+ *flags |= FLAG_BYTEORDER_NATIVE;
+ }
+ else {
return MRB_DUMP_INVALID_FILE_HEADER;
}
- *crc = bin_to_uint16(header->binary_crc);
- if (bin_size) {
- *bin_size = (size_t)bin_to_uint32(header->binary_size);
+ if (crc) {
+ *crc = bin_to_uint16(header->binary_crc);
}
+ *bin_size = (size_t)bin_to_uint32(header->binary_size);
return MRB_DUMP_OK;
}
-mrb_irep*
-mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
+MRB_API mrb_irep*
+read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
{
int result;
mrb_irep *irep = NULL;
@@ -520,7 +558,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
return NULL;
}
- result = read_binary_header(bin, &bin_size, &crc);
+ result = read_binary_header(bin, &bin_size, &crc, &flags);
if (result != MRB_DUMP_OK) {
return NULL;
}
@@ -533,48 +571,59 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
bin += sizeof(struct rite_binary_header);
do {
section_header = (const struct rite_section_header *)bin;
- if (memcmp(section_header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
- irep = read_section_irep(mrb, bin, FALSE);
+ if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) {
+ irep = read_section_irep(mrb, bin, flags);
if (!irep) return NULL;
}
- else if (memcmp(section_header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) {
if (!irep) return NULL; /* corrupted data */
result = read_section_lineno(mrb, bin, irep);
if (result < MRB_DUMP_OK) {
return NULL;
}
}
- else if (memcmp(section_header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) {
if (!irep) return NULL; /* corrupted data */
- result = read_section_debug(mrb, bin, irep, FALSE);
+ result = read_section_debug(mrb, bin, irep, flags);
if (result < MRB_DUMP_OK) {
return NULL;
}
}
- else if (memcmp(section_header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) {
if (!irep) return NULL;
- result = read_section_lv(mrb, bin, irep, FALSE);
+ result = read_section_lv(mrb, bin, irep, flags);
if (result < MRB_DUMP_OK) {
return NULL;
}
}
bin += bin_to_uint32(section_header->section_size);
- } while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0);
+ } while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0);
return irep;
}
+MRB_API mrb_irep*
+mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
+{
+#ifdef MRB_USE_ETEXT_EDATA
+ uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
+#else
+ uint8_t flags = FLAG_SRC_STATIC;
+#endif
+
+ return read_irep(mrb, bin, flags);
+}
+
static void
irep_error(mrb_state *mrb)
{
mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
-mrb_value
+MRB_API mrb_value
mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
{
mrb_irep *irep = mrb_read_irep(mrb, bin);
- mrb_value val;
struct RProc *proc;
if (!irep) {
@@ -584,224 +633,54 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
proc = mrb_proc_new(mrb, irep);
mrb_irep_decref(mrb, irep);
if (c && c->no_exec) return mrb_obj_value(proc);
- val = mrb_toplevel_run(mrb, proc);
- return val;
+ return mrb_toplevel_run(mrb, proc);
}
-mrb_value
+MRB_API mrb_value
mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
{
return mrb_load_irep_cxt(mrb, bin, NULL);
}
-#ifdef ENABLE_STDIO
-
-static int
-read_lineno_record_file(mrb_state *mrb, FILE *fp, mrb_irep *irep)
-{
- uint8_t header[4];
- const size_t record_header_size = sizeof(header);
- int result;
- size_t i, buf_size;
- size_t len;
- void *ptr;
- uint8_t *buf;
-
- if (fread(header, record_header_size, 1, fp) == 0) {
- return MRB_DUMP_READ_FAULT;
- }
- buf_size = (size_t)bin_to_uint32(&header[0]);
- if (SIZE_ERROR(buf_size)) {
- return MRB_DUMP_GENERAL_FAILURE;
- }
- ptr = mrb_malloc(mrb, buf_size);
- buf = (uint8_t *)ptr;
-
- if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
- return MRB_DUMP_READ_FAULT;
- }
- result = read_lineno_record_1(mrb, buf, irep, &len);
- mrb_free(mrb, ptr);
- if (result != MRB_DUMP_OK) return result;
- for (i = 0; i < irep->rlen; i++) {
- result = read_lineno_record_file(mrb, fp, irep->reps[i]);
- if (result != MRB_DUMP_OK) break;
- }
- return result;
-}
-
-static int32_t
-read_section_lineno_file(mrb_state *mrb, FILE *fp, mrb_irep *irep)
-{
- struct rite_section_lineno_header header;
-
- if (fread(&header, sizeof(struct rite_section_lineno_header), 1, fp) == 0) {
- return MRB_DUMP_READ_FAULT;
- }
-
- /* Read Binary Data Section */
- return read_lineno_record_file(mrb, fp, irep);
-}
+#ifndef MRB_DISABLE_STDIO
-static mrb_irep*
-read_irep_record_file(mrb_state *mrb, FILE *fp)
-{
- uint8_t header[1 + 4];
- const size_t record_header_size = sizeof(header);
- size_t buf_size, i;
- size_t len;
- mrb_irep *irep = NULL;
- void *ptr;
- uint8_t *buf;
-
- if (fread(header, record_header_size, 1, fp) == 0) {
- return NULL;
- }
- buf_size = (size_t)bin_to_uint32(&header[0]);
- if (SIZE_ERROR(buf_size)) {
- return NULL;
- }
- ptr = mrb_malloc(mrb, buf_size);
- buf = (uint8_t *)ptr;
- memcpy(buf, header, record_header_size);
- if (fread(&buf[record_header_size], buf_size - record_header_size, 1, fp) == 0) {
- return NULL;
- }
- irep = read_irep_record_1(mrb, buf, &len, TRUE);
- mrb_free(mrb, ptr);
- if (!irep) return NULL;
- for (i=0; i<irep->rlen; i++) {
- irep->reps[i] = read_irep_record_file(mrb, fp);
- if (!irep->reps[i]) return NULL;
- }
- return irep;
-}
-
-static mrb_irep*
-read_section_irep_file(mrb_state *mrb, FILE *fp)
-{
- struct rite_section_irep_header header;
-
- if (fread(&header, sizeof(struct rite_section_irep_header), 1, fp) == 0) {
- return NULL;
- }
- return read_irep_record_file(mrb, fp);
-}
-
-mrb_irep*
+MRB_API mrb_irep*
mrb_read_irep_file(mrb_state *mrb, FILE* fp)
{
mrb_irep *irep = NULL;
- int result;
uint8_t *buf;
- uint16_t crc, crcwk = 0;
- size_t section_size = 0;
- size_t nbytes;
- struct rite_section_header section_header;
- long fpos;
- size_t block_size = 1 << 14;
- const uint8_t block_fallback_count = 4;
- int i;
- const size_t buf_size = sizeof(struct rite_binary_header);
+ const size_t header_size = sizeof(struct rite_binary_header);
+ size_t buf_size = 0;
+ uint8_t flags = 0;
+ int result;
if ((mrb == NULL) || (fp == NULL)) {
return NULL;
}
- /* You don't need use SIZE_ERROR as buf_size is enough small. */
- buf = (uint8_t*)mrb_malloc(mrb, buf_size);
- if (fread(buf, buf_size, 1, fp) == 0) {
- mrb_free(mrb, buf);
- return NULL;
+ buf = (uint8_t*)mrb_malloc(mrb, header_size);
+ if (fread(buf, header_size, 1, fp) == 0) {
+ goto irep_exit;
}
- result = read_binary_header(buf, NULL, &crc);
- mrb_free(mrb, buf);
- if (result != MRB_DUMP_OK) {
- return NULL;
+ result = read_binary_header(buf, &buf_size, NULL, &flags);
+ if (result != MRB_DUMP_OK || buf_size <= header_size) {
+ goto irep_exit;
}
- /* verify CRC */
- fpos = ftell(fp);
- /* You don't need use SIZE_ERROR as block_size is enough small. */
- for (i = 0; i < block_fallback_count; i++,block_size >>= 1) {
- buf = (uint8_t*)mrb_malloc_simple(mrb, block_size);
- if (buf) break;
+ buf = (uint8_t*)mrb_realloc(mrb, buf, buf_size);
+ if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) {
+ goto irep_exit;
}
- if (!buf) {
- return NULL;
- }
- fseek(fp, offset_crc_body(), SEEK_SET);
- while ((nbytes = fread(buf, 1, block_size, fp)) > 0) {
- crcwk = calc_crc_16_ccitt(buf, nbytes, crcwk);
- }
- mrb_free(mrb, buf);
- if (nbytes == 0 && ferror(fp)) {
- return NULL;
- }
- if (crcwk != crc) {
- return NULL;
- }
- fseek(fp, fpos + section_size, SEEK_SET);
-
- /* read sections */
- do {
- fpos = ftell(fp);
- if (fread(&section_header, sizeof(struct rite_section_header), 1, fp) == 0) {
- return NULL;
- }
- section_size = (size_t)bin_to_uint32(section_header.section_size);
-
- if (memcmp(section_header.section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
- fseek(fp, fpos, SEEK_SET);
- irep = read_section_irep_file(mrb, fp);
- if (!irep) return NULL;
- }
- else if (memcmp(section_header.section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
- if (!irep) return NULL; /* corrupted data */
- fseek(fp, fpos, SEEK_SET);
- result = read_section_lineno_file(mrb, fp, irep);
- if (result < MRB_DUMP_OK) return NULL;
- }
- else if (memcmp(section_header.section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
- if (!irep) return NULL; /* corrupted data */
- else {
- uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size);
-
- fseek(fp, fpos, SEEK_SET);
- if (fread((char*)bin, section_size, 1, fp) != 1) {
- mrb_free(mrb, bin);
- return NULL;
- }
- result = read_section_debug(mrb, bin, irep, TRUE);
- mrb_free(mrb, bin);
- }
- if (result < MRB_DUMP_OK) return NULL;
- }
- else if (memcmp(section_header.section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
- if (!irep) return NULL;
- else {
- uint8_t* const bin = (uint8_t*)mrb_malloc(mrb, section_size);
-
- fseek(fp, fpos, SEEK_SET);
- if (fread((char*)bin, section_size, 1, fp) != 1) {
- mrb_free(mrb, bin);
- return NULL;
- }
- result = read_section_lv(mrb, bin, irep, TRUE);
- mrb_free(mrb, bin);
- }
- if (result < MRB_DUMP_OK) return NULL;
- }
-
- fseek(fp, fpos + section_size, SEEK_SET);
- } while (memcmp(section_header.section_identify, RITE_BINARY_EOF, sizeof(section_header.section_identify)) != 0);
+ irep = read_irep(mrb, buf, FLAG_SRC_MALLOC);
+irep_exit:
+ mrb_free(mrb, buf);
return irep;
}
void mrb_codedump_all(mrb_state*, struct RProc*);
-mrb_value
+MRB_API mrb_value
mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
{
mrb_irep *irep = mrb_read_irep_file(mrb, fp);
@@ -820,9 +699,9 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
return val;
}
-mrb_value
+MRB_API mrb_value
mrb_load_irep_file(mrb_state *mrb, FILE* fp)
{
return mrb_load_irep_file_cxt(mrb, fp, NULL);
}
-#endif /* ENABLE_STDIO */
+#endif /* MRB_DISABLE_STDIO */
diff --git a/src/mrb_throw.h b/src/mrb_throw.h
deleted file mode 100644
index 3c7407a8d..000000000
--- a/src/mrb_throw.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-** mrb_throw.h - mruby exception throwing handler
-**
-** See Copyright Notice in mruby.h
-*/
-
-#ifndef MRB_THROW_H
-#define MRB_THROW_H
-
-#ifdef MRB_ENABLE_CXX_EXCEPTION
-
-#define MRB_TRY(buf) do { try {
-#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; }
-#define MRB_END_EXC(buf) } } while(0)
-
-#define MRB_THROW(buf) throw((buf)->impl)
-typedef mrb_int mrb_jmpbuf_impl;
-
-#else
-
-#include <setjmp.h>
-
-#define MRB_TRY(buf) do { if (setjmp((buf)->impl) == 0) {
-#define MRB_CATCH(buf) } else {
-#define MRB_END_EXC(buf) } } while(0)
-
-#define MRB_THROW(buf) longjmp((buf)->impl, 1);
-#define mrb_jmpbuf_impl jmp_buf
-
-#endif
-
-struct mrb_jmpbuf {
- mrb_jmpbuf_impl impl;
-
-#ifdef MRB_ENABLE_CXX_EXCEPTION
- static mrb_int jmpbuf_id;
- mrb_jmpbuf() : impl(jmpbuf_id++) {}
-#endif
-};
-
-#endif /* MRB_THROW_H */
diff --git a/src/mruby_core.rake b/src/mruby_core.rake
index 88fca83fc..abde441d5 100644
--- a/src/mruby_core.rake
+++ b/src/mruby_core.rake
@@ -3,76 +3,17 @@ MRuby.each_target do
relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT)
current_build_dir = "#{build_dir}/#{relative_from_root}"
- lex_def = "#{current_dir}/lex.def"
objs = Dir.glob("#{current_dir}/*.c").map { |f|
- next nil if cxx_abi_enabled? and f =~ /(codegen|error|vm).c$/
+ next nil if cxx_abi_enabled? and f =~ /(error|vm).c$/
objfile(f.pathmap("#{current_build_dir}/%n"))
}.compact
if cxx_abi_enabled?
- cxx_abi_dependency = %w(codegen error vm)
- cxx_abi_objs = cxx_abi_dependency.map { |v|
- src = "#{current_build_dir}/#{v}.cxx"
- file src => ["#{current_dir}/#{v}.c", __FILE__] do |t|
- File.open(t.name, 'w') do |f|
- f.write <<EOS
-#define __STDC_CONSTANT_MACROS
-#define __STDC_LIMIT_MACROS
-
-extern "C" {
-#include "#{MRUBY_ROOT}/#{t.prerequisites.first}"
-}
-
-
-#{v == 'error'? 'mrb_int mrb_jmpbuf::jmpbuf_id = 0;' : ''}
-EOS
- end
- end
-
- file objfile(src) => src do |t|
- cxx.run t.name, t.prerequisites.first, [], [current_dir]
- end
-
- objfile src
- }
- cxx_abi_objs << objfile("#{current_build_dir}/y.tab")
-
- file "#{current_build_dir}/y.tab.cxx" => ["#{current_build_dir}/y.tab.c", __FILE__] do |t|
- File.open(t.name, 'w') do |f|
- f.write <<EOS
-#define __STDC_CONSTANT_MACROS
-#define __STDC_LIMIT_MACROS
-
-extern "C" {
-#include "#{t.prerequisites.first}"
-}
-EOS
- end
- end
- file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.cxx", lex_def] do |t|
- cxx.run t.name, t.prerequisites.first, [], [current_dir]
- end
-
- objs += cxx_abi_objs
- else
- objs += [objfile("#{current_build_dir}/y.tab")]
- file objfile("#{current_build_dir}/y.tab") => ["#{current_build_dir}/y.tab.c", lex_def] do |t|
- cc.run t.name, t.prerequisites.first, [], [current_dir]
- end
+ objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" }
end
self.libmruby << objs
file libfile("#{build_dir}/lib/libmruby_core") => objs do |t|
archiver.run t.name, t.prerequisites
end
-
- # Parser
- file "#{current_build_dir}/y.tab.c" => ["#{current_dir}/parse.y"] do |t|
- yacc.run t.name, t.prerequisites.first
- end
-
- # Lexical analyzer
- file lex_def => "#{current_dir}/keywords" do |t|
- gperf.run t.name, t.prerequisites.first
- end
end
diff --git a/src/node.h b/src/node.h
deleted file mode 100644
index 532a8323a..000000000
--- a/src/node.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-** node.h - nodes of abstract syntax tree
-**
-** See Copyright Notice in mruby.h
-*/
-
-#ifndef NODE_H
-#define NODE_H
-
-enum node_type {
- NODE_METHOD,
- NODE_FBODY,
- NODE_CFUNC,
- NODE_SCOPE,
- NODE_BLOCK,
- NODE_IF,
- NODE_CASE,
- NODE_WHEN,
- NODE_OPT_N,
- NODE_WHILE,
- NODE_UNTIL,
- NODE_ITER,
- NODE_FOR,
- NODE_BREAK,
- NODE_NEXT,
- NODE_REDO,
- NODE_RETRY,
- NODE_BEGIN,
- NODE_RESCUE,
- NODE_ENSURE,
- NODE_AND,
- NODE_OR,
- NODE_NOT,
- NODE_MASGN,
- NODE_ASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_CVDECL,
- NODE_OP_ASGN,
- NODE_CALL,
- NODE_FCALL,
- NODE_VCALL,
- NODE_SUPER,
- NODE_ZSUPER,
- NODE_ARRAY,
- NODE_ZARRAY,
- NODE_HASH,
- NODE_RETURN,
- NODE_YIELD,
- NODE_LVAR,
- NODE_DVAR,
- NODE_GVAR,
- NODE_IVAR,
- NODE_CONST,
- NODE_CVAR,
- NODE_NTH_REF,
- NODE_BACK_REF,
- NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
- NODE_INT,
- NODE_FLOAT,
- NODE_NEGATE,
- NODE_LAMBDA,
- NODE_SYM,
- NODE_STR,
- NODE_DSTR,
- NODE_XSTR,
- NODE_DXSTR,
- NODE_REGX,
- NODE_DREGX,
- NODE_DREGX_ONCE,
- NODE_LIST,
- NODE_ARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
- NODE_SPLAT,
- NODE_TO_ARY,
- NODE_SVALUE,
- NODE_BLOCK_ARG,
- NODE_DEF,
- NODE_SDEF,
- NODE_ALIAS,
- NODE_UNDEF,
- NODE_CLASS,
- NODE_MODULE,
- NODE_SCLASS,
- NODE_COLON2,
- NODE_COLON3,
- NODE_CREF,
- NODE_DOT2,
- NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_ATTRSET,
- NODE_SELF,
- NODE_NIL,
- NODE_TRUE,
- NODE_FALSE,
- NODE_DEFINED,
- NODE_NEWLINE,
- NODE_POSTEXE,
- NODE_ALLOCA,
- NODE_DMETHOD,
- NODE_BMETHOD,
- NODE_MEMO,
- NODE_IFUNC,
- NODE_DSYM,
- NODE_ATTRASGN,
- NODE_HEREDOC,
- NODE_LITERAL_DELIM,
- NODE_WORDS,
- NODE_SYMBOLS,
- NODE_LAST
-};
-
-#endif /* NODE_H */
diff --git a/src/numeric.c b/src/numeric.c
index db1e7d0f4..7b49b29f7 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -9,25 +9,21 @@
#include <math.h>
#include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
#ifdef MRB_USE_FLOAT
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define FLO_MAX_DIGITS 7
-#define FLO_MAX_SIGN_LENGTH 3
-#define FLO_EPSILON FLT_EPSILON
+#define MRB_FLO_TO_STR_FMT "%.7g"
#else
-#define FLO_MAX_DIGITS 14
-#define FLO_MAX_SIGN_LENGTH 10
-#define FLO_EPSILON DBL_EPSILON
+#define MRB_FLO_TO_STR_FMT "%.14g"
#endif
-mrb_float
+MRB_API mrb_float
mrb_to_flo(mrb_state *mrb, mrb_value val)
{
switch (mrb_type(val)) {
@@ -54,13 +50,13 @@ static mrb_value
num_pow(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_bool both_int = FALSE;
- mrb_float d;
+ mrb_float d, yv;
mrb_get_args(mrb, "o", &y);
- if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) both_int = TRUE;
- d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
- if (both_int && FIXABLE(d))
+ yv = mrb_to_flo(mrb, y);
+ d = pow(mrb_to_flo(mrb, x), yv);
+ if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0 &&
+ (d < 0 || (d > 0 && (mrb_int)d > 0)))
return mrb_fixnum_value((mrb_int)d);
return mrb_float_value(mrb, d);
}
@@ -108,142 +104,6 @@ num_div(mrb_state *mrb, mrb_value x)
* representation.
*/
-static mrb_value
-mrb_flo_to_str(mrb_state *mrb, mrb_float flo)
-{
- double n = (double)flo;
- int max_digits = FLO_MAX_DIGITS;
-
- if (isnan(n)) {
- return mrb_str_new_lit(mrb, "NaN");
- }
- else if (isinf(n)) {
- if (n < 0) {
- return mrb_str_new_lit(mrb, "-inf");
- }
- else {
- return mrb_str_new_lit(mrb, "inf");
- }
- }
- else {
- int digit;
- int m = 0;
- int exp;
- mrb_bool e = FALSE;
- char s[48];
- char *c = &s[0];
- int length = 0;
-
- if (signbit(n)) {
- n = -n;
- *(c++) = '-';
- }
-
- if (n != 0.0) {
- if (n > 1.0) {
- exp = (int)floor(log10(n));
- }
- else {
- exp = (int)-ceil(-log10(n));
- }
- }
- else {
- exp = 0;
- }
-
- /* preserve significands */
- if (exp < 0) {
- int i, beg = -1, end = 0;
- double f = n;
- double fd = 0;
- for (i = 0; i < FLO_MAX_DIGITS; ++i) {
- f = (f - fd) * 10.0;
- fd = floor(f + FLO_EPSILON);
- if (fd != 0) {
- if (beg < 0) beg = i;
- end = i + 1;
- }
- }
- if (beg >= 0) length = end - beg;
- if (length > FLO_MAX_SIGN_LENGTH) length = FLO_MAX_SIGN_LENGTH;
- }
-
- if (abs(exp) + length >= FLO_MAX_DIGITS) {
- /* exponent representation */
- e = TRUE;
- n = n / pow(10.0, exp);
- if (isinf(n)) {
- if (s < c) { /* s[0] == '-' */
- return mrb_str_new_lit(mrb, "-0.0");
- }
- else {
- return mrb_str_new_lit(mrb, "0.0");
- }
- }
- }
- else {
- /* un-exponent (normal) representation */
- if (exp > 0) {
- m = exp;
- }
- }
-
- /* puts digits */
- while (max_digits >= 0) {
- double weight = pow(10.0, m);
- double fdigit = n / weight;
-
- if (fdigit < 0) fdigit = n = 0;
- if (m < -1 && fdigit < FLO_EPSILON) {
- if (e || exp > 0 || m <= -abs(exp)) {
- break;
- }
- }
- digit = (int)floor(fdigit + FLO_EPSILON);
- if (m == 0 && digit > 9) {
- n /= 10.0;
- exp++;
- continue;
- }
- *(c++) = '0' + digit;
- n -= (digit * weight);
- max_digits--;
- if (m-- == 0) {
- *(c++) = '.';
- }
- }
- if (c[-1] == '0') {
- while (&s[0] < c && c[-1] == '0') {
- c--;
- }
- c++;
- }
-
- if (e) {
- *(c++) = 'e';
- if (exp > 0) {
- *(c++) = '+';
- }
- else {
- *(c++) = '-';
- exp = -exp;
- }
-
- if (exp >= 100) {
- *(c++) = '0' + exp / 100;
- exp -= exp / 100 * 100;
- }
-
- *(c++) = '0' + exp / 10;
- *(c++) = '0' + exp % 10;
- }
-
- *c = '\0';
-
- return mrb_str_new(mrb, &s[0], c - &s[0]);
- }
-}
-
/* 15.2.9.3.16(x) */
/*
* call-seq:
@@ -251,14 +111,17 @@ mrb_flo_to_str(mrb_state *mrb, mrb_float flo)
*
* Returns a string containing a representation of self. As well as a
* fixed or exponential form of the number, the call may return
- * ``<code>NaN</code>'', ``<code>Infinity</code>'', and
- * ``<code>-Infinity</code>''.
+ * "<code>NaN</code>", "<code>Infinity</code>", and
+ * "<code>-Infinity</code>".
*/
static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
- return mrb_flo_to_str(mrb, mrb_float(flt));
+ if (isnan(mrb_float(flt))) {
+ return mrb_str_new_lit(mrb, "NaN");
+ }
+ return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
}
/* 15.2.9.3.2 */
@@ -339,12 +202,11 @@ static mrb_value
flo_mod(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_float fy, mod;
+ mrb_float mod;
mrb_get_args(mrb, "o", &y);
- fy = mrb_to_flo(mrb, y);
- flodivmod(mrb, mrb_float(x), fy, 0, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
return mrb_float_value(mrb, mod);
}
@@ -397,22 +259,16 @@ static mrb_value
flo_eq(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- volatile mrb_float a, b;
-
mrb_get_args(mrb, "o", &y);
switch (mrb_type(y)) {
case MRB_TT_FIXNUM:
- b = (mrb_float)mrb_fixnum(y);
- break;
+ return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
case MRB_TT_FLOAT:
- b = mrb_float(y);
- break;
+ return mrb_bool_value(mrb_float(x) == mrb_float(y));
default:
return mrb_false_value();
}
- a = mrb_float(x);
- return mrb_bool_value(a == b);
}
/* 15.2.8.3.18 */
@@ -474,7 +330,7 @@ flo_infinite_p(mrb_state *mrb, mrb_value num)
mrb_float value = mrb_float(num);
if (isinf(value)) {
- return mrb_fixnum_value( value < 0 ? -1 : 1 );
+ return mrb_fixnum_value(value < 0 ? -1 : 1);
}
return mrb_nil_value();
}
@@ -493,9 +349,7 @@ flo_infinite_p(mrb_state *mrb, mrb_value num)
static mrb_value
flo_finite_p(mrb_state *mrb, mrb_value num)
{
- mrb_float value = mrb_float(num);
-
- return mrb_bool_value(isfinite(value));
+ return mrb_bool_value(isfinite(mrb_float(num)));
}
/* 15.2.9.3.10 */
@@ -583,7 +437,7 @@ flo_round(mrb_state *mrb, mrb_value num)
{
double number, f;
mrb_int ndigits = 0;
- int i;
+ mrb_int i;
mrb_get_args(mrb, "|i", &ndigits);
number = mrb_float(num);
@@ -598,7 +452,7 @@ flo_round(mrb_state *mrb, mrb_value num)
}
f = 1.0;
- i = abs(ndigits);
+ i = ndigits >= 0 ? ndigits : -ndigits;
while (--i >= 0)
f = f*10.0;
@@ -613,12 +467,12 @@ flo_round(mrb_state *mrb, mrb_value num)
/* home-made inline implementation of round(3) */
if (number > 0.0) {
- d = floor(number);
- number = d + (number - d >= 0.5);
+ d = floor(number);
+ number = d + (number - d >= 0.5);
}
else if (number < 0.0) {
- d = ceil(number);
- number = d - (d - number >= 0.5);
+ d = ceil(number);
+ number = d - (d - number >= 0.5);
}
if (ndigits < 0) number *= f;
@@ -687,12 +541,8 @@ int_to_i(mrb_state *mrb, mrb_value num)
return num;
}
-#ifdef MRB_FIXNUM_SHIFT
-#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1-MRB_FIXNUM_SHIFT)/2))
-#else
-#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1)/2))
-#endif
/*tests if N*N would overflow*/
+#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1-MRB_FIXNUM_SHIFT)/2))
#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
mrb_value
@@ -713,7 +563,7 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
if ((a != 0 && c/a != b) || !FIXABLE(c)) {
return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b);
}
- return mrb_fixnum_value(c);
+ return mrb_fixnum_value((mrb_int)c);
}
return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
}
@@ -970,19 +820,35 @@ fix_xor(mrb_state *mrb, mrb_value x)
static mrb_value
lshift(mrb_state *mrb, mrb_int val, mrb_int width)
{
- mrb_assert(width >= 0);
- if (width > NUMERIC_SHIFT_WIDTH_MAX) {
- mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)",
- mrb_fixnum_value(width),
- mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX));
+ mrb_assert(width > 0);
+ if (val > 0) {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val > (MRB_INT_MAX >> width))) {
+ goto bit_overflow;
+ }
+ } else {
+ if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
+ (val < (MRB_INT_MIN >> width))) {
+ goto bit_overflow;
+ }
}
+
return mrb_fixnum_value(val << width);
+
+bit_overflow:
+ {
+ mrb_float f = (mrb_float)val;
+ while (width--) {
+ f *= 2;
+ }
+ return mrb_float_value(mrb, f);
+ }
}
static mrb_value
rshift(mrb_int val, mrb_int width)
{
- mrb_assert(width >= 0);
+ mrb_assert(width > 0);
if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
if (val < 0) {
return mrb_fixnum_value(-1);
@@ -1004,7 +870,7 @@ fix_shift_get_width(mrb_state *mrb, mrb_int *width)
/* 15.2.8.3.12 */
/*
* call-seq:
- * fix << count -> integer
+ * fix << count -> integer or float
*
* Shifts _fix_ left _count_ positions (right if _count_ is negative).
*/
@@ -1029,7 +895,7 @@ fix_lshift(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.13 */
/*
* call-seq:
- * fix >> count -> integer
+ * fix >> count -> integer or float
*
* Shifts _fix_ right _count_ positions (left if _count_ is negative).
*/
@@ -1080,14 +946,14 @@ fix_to_f(mrb_state *mrb, mrb_value num)
* FloatDomainError: Infinity
*/
/* ------------------------------------------------------------------------*/
-mrb_value
+MRB_API mrb_value
mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
{
mrb_int z;
- if (mrb_float_p(x)) {
- mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- z = 0; /* not reached. just suppress warnings. */
+ if (!mrb_float_p(x)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "non float value");
+ z = 0; /* not reached. just suppress warnings. */
}
else {
mrb_float d = mrb_float(x);
@@ -1098,7 +964,12 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
if (isnan(d)) {
mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
}
- z = (mrb_int)d;
+ if (FIXABLE(d)) {
+ z = (mrb_int)d;
+ }
+ else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x);
+ }
}
return mrb_fixnum_value(z);
}
@@ -1178,7 +1049,7 @@ fix_minus(mrb_state *mrb, mrb_value self)
}
-mrb_value
+MRB_API mrb_value
mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
{
char buf[MRB_INT_BIT+1];
@@ -1309,7 +1180,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
/* Fixnum Class */
- fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
+ mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
@@ -1329,7 +1200,7 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
/* Float Class */
- fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
+ mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
mrb_undef_class_method(mrb, fl, "new");
mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
@@ -1351,4 +1222,11 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
+
+#ifdef INFINITY
+ mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
+#endif
+#ifdef NAN
+ mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
+#endif
}
diff --git a/src/object.c b/src/object.c
index 6d39254dd..bb1a4ebc4 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,12 +4,12 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
-mrb_bool
+MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
if (mrb_type(v1) != mrb_type(v2)) return FALSE;
@@ -19,9 +19,9 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
case MRB_TT_FALSE:
case MRB_TT_FIXNUM:
- return (v1.value.i == v2.value.i);
+ return (mrb_fixnum(v1) == mrb_fixnum(v2));
case MRB_TT_SYMBOL:
- return (v1.value.sym == v2.value.sym);
+ return (mrb_symbol(v1) == mrb_symbol(v2));
case MRB_TT_FLOAT:
return (mrb_float(v1) == mrb_float(v2));
@@ -31,14 +31,14 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
}
}
-mrb_bool
+MRB_API mrb_bool
mrb_obj_equal(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
/* temporary definition */
return mrb_obj_eq(mrb, v1, v2);
}
-mrb_bool
+MRB_API mrb_bool
mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
{
mrb_value result;
@@ -264,7 +264,7 @@ mrb_init_object(mrb_state *mrb)
struct RClass *t;
struct RClass *f;
- n = mrb->nil_class = mrb_define_class(mrb, "NilClass", mrb->object_class);
+ mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class);
mrb_undef_class_method(mrb, n, "new");
mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */
mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */
@@ -273,7 +273,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, n, "to_s", nil_to_s, MRB_ARGS_NONE()); /* 15.2.4.3.5 */
mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE());
- t = mrb->true_class = mrb_define_class(mrb, "TrueClass", mrb->object_class);
+ mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class);
mrb_undef_class_method(mrb, t, "new");
mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */
mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */
@@ -281,7 +281,7 @@ mrb_init_object(mrb_state *mrb)
mrb_define_method(mrb, t, "|", true_or, MRB_ARGS_REQ(1)); /* 15.2.5.3.4 */
mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE());
- f = mrb->false_class = mrb_define_class(mrb, "FalseClass", mrb->object_class);
+ mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class);
mrb_undef_class_method(mrb, f, "new");
mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */
mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */
@@ -310,16 +310,13 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho
if (!mrb_respond_to(mrb, val, m)) {
if (raise) {
mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname));
- return mrb_nil_value();
- }
- else {
- return mrb_nil_value();
}
+ return mrb_nil_value();
}
return mrb_funcall_argv(mrb, val, m, 0, 0);
}
-mrb_value
+MRB_API mrb_value
mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method)
{
mrb_value v;
@@ -332,7 +329,7 @@ mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method)
return v;
}
-mrb_value
+MRB_API mrb_value
mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method)
{
mrb_value v;
@@ -346,7 +343,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char
return v;
}
-mrb_value
+MRB_API mrb_value
mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method)
{
mrb_value v;
@@ -386,7 +383,7 @@ static const struct types {
{-1, 0}
};
-void
+MRB_API void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
const struct types *type = builtin_types;
@@ -407,7 +404,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
else if (mrb_type(x) == MRB_TT_SYMBOL) {
etype = "Symbol";
}
- else if (mrb_special_const_p(x)) {
+ else if (mrb_immediate_p(x)) {
etype = RSTRING_PTR(mrb_obj_as_string(mrb, x));
}
else {
@@ -431,10 +428,10 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
* Returns a string representing <i>obj</i>. The default
* <code>to_s</code> prints the object's class and an encoding of the
* object id. As a special case, the top-level object that is the
- * initial execution context of Ruby programs returns ``main.''
+ * initial execution context of Ruby programs returns "main."
*/
-mrb_value
+MRB_API mrb_value
mrb_any_to_s(mrb_state *mrb, mrb_value obj)
{
mrb_value str = mrb_str_buf_new(mrb, 20);
@@ -475,7 +472,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
* b.kind_of? M #=> true
*/
-mrb_bool
+MRB_API mrb_bool
mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
{
struct RClass *cl = mrb_class(mrb, obj);
@@ -484,12 +481,14 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
case MRB_TT_MODULE:
case MRB_TT_CLASS:
case MRB_TT_ICLASS:
+ case MRB_TT_SCLASS:
break;
default:
mrb_raise(mrb, E_TYPE_ERROR, "class or module required");
}
+ MRB_CLASS_ORIGIN(c);
while (cl) {
if (cl == c || cl->mt == c->mt)
return TRUE;
@@ -513,13 +512,13 @@ mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method)
return v;
}
-mrb_value
+MRB_API mrb_value
mrb_to_int(mrb_state *mrb, mrb_value val)
{
return mrb_to_integer(mrb, val, "to_int");
}
-static mrb_value
+MRB_API mrb_value
mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
{
mrb_value tmp;
@@ -540,13 +539,17 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base)
if (base != 0) goto arg_error;
return val;
+ case MRB_TT_STRING:
+ string_conv:
+ return mrb_str_to_inum(mrb, val, base, TRUE);
+
default:
break;
}
if (base != 0) {
tmp = mrb_check_string_type(mrb, val);
if (!mrb_nil_p(tmp)) {
- return mrb_str_to_inum(mrb, val, base, TRUE);
+ goto string_conv;
}
arg_error:
mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
@@ -558,13 +561,13 @@ arg_error:
return tmp;
}
-mrb_value
+MRB_API mrb_value
mrb_Integer(mrb_state *mrb, mrb_value val)
{
return mrb_convert_to_integer(mrb, val, 0);
}
-mrb_value
+MRB_API mrb_value
mrb_Float(mrb_state *mrb, mrb_value val)
{
if (mrb_nil_p(val)) {
@@ -585,13 +588,13 @@ mrb_Float(mrb_state *mrb, mrb_value val)
}
}
-mrb_value
+MRB_API mrb_value
mrb_inspect(mrb_state *mrb, mrb_value obj)
{
return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0));
}
-mrb_bool
+MRB_API mrb_bool
mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
{
if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE;
diff --git a/src/opcode.h b/src/opcode.h
index 2446f92ed..fe4d17a21 100644
--- a/src/opcode.h
+++ b/src/opcode.h
@@ -1,2 +1,2 @@
/* this header file is to be removed soon. */
-#include "mruby/opcode.h"
+#include <mruby/opcode.h>
diff --git a/src/parse.y b/src/parse.y
deleted file mode 100644
index 2c7e788d9..000000000
--- a/src/parse.y
+++ /dev/null
@@ -1,6370 +0,0 @@
-/*
-** parse.y - mruby parser
-**
-** See Copyright Notice in mruby.h
-*/
-
-%{
-#undef PARSER_DEBUG
-
-#define YYDEBUG 1
-#define YYERROR_VERBOSE 1
-/*
- * Force yacc to use our memory management. This is a little evil because
- * the macros assume that "parser_state *p" is in scope
- */
-#define YYMALLOC(n) mrb_malloc(p->mrb, (n))
-#define YYFREE(o) mrb_free(p->mrb, (o))
-#define YYSTACK_USE_ALLOCA 0
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "mruby.h"
-#include "mruby/compile.h"
-#include "mruby/proc.h"
-#include "mruby/error.h"
-#include "node.h"
-#include "mrb_throw.h"
-
-#define YYLEX_PARAM p
-
-typedef mrb_ast_node node;
-typedef struct mrb_parser_state parser_state;
-typedef struct mrb_parser_heredoc_info parser_heredoc_info;
-
-static int yyparse(parser_state *p);
-static int yylex(void *lval, parser_state *p);
-static void yyerror(parser_state *p, const char *s);
-static void yywarn(parser_state *p, const char *s);
-static void yywarning(parser_state *p, const char *s);
-static void backref_error(parser_state *p, node *n);
-static void tokadd(parser_state *p, int32_t c);
-
-#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
-
-typedef unsigned int stack_type;
-
-#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1))
-#define BITSTACK_POP(stack) ((stack) = (stack) >> 1)
-#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1))
-#define BITSTACK_SET_P(stack) ((stack)&1)
-
-#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n))
-#define COND_POP() BITSTACK_POP(p->cond_stack)
-#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack)
-#define COND_P() BITSTACK_SET_P(p->cond_stack)
-
-#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n))
-#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack)
-#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack)
-#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack)
-
-#define SET_LINENO(c,n) ((c)->lineno = (n))
-
-#define sym(x) ((mrb_sym)(intptr_t)(x))
-#define nsym(x) ((node*)(intptr_t)(x))
-
-static inline mrb_sym
-intern_cstr_gen(parser_state *p, const char *s)
-{
- return mrb_intern_cstr(p->mrb, s);
-}
-#define intern_cstr(s) intern_cstr_gen(p,(s))
-
-static inline mrb_sym
-intern_gen(parser_state *p, const char *s, size_t len)
-{
- return mrb_intern(p->mrb, s, len);
-}
-#define intern(s,len) intern_gen(p,(s),(len))
-
-static inline mrb_sym
-intern_gen_c(parser_state *p, const char c)
-{
- return mrb_intern(p->mrb, &c, 1);
-}
-#define intern_c(c) intern_gen_c(p,(c))
-
-static void
-cons_free_gen(parser_state *p, node *cons)
-{
- cons->cdr = p->cells;
- p->cells = cons;
-}
-#define cons_free(c) cons_free_gen(p, (c))
-
-static void*
-parser_palloc(parser_state *p, size_t size)
-{
- void *m = mrb_pool_alloc(p->pool, size);
-
- if (!m) {
- MRB_THROW(p->jmp);
- }
- return m;
-}
-
-static node*
-cons_gen(parser_state *p, node *car, node *cdr)
-{
- node *c;
-
- if (p->cells) {
- c = p->cells;
- p->cells = p->cells->cdr;
- }
- else {
- c = (node *)parser_palloc(p, sizeof(mrb_ast_node));
- }
-
- c->car = car;
- c->cdr = cdr;
- c->lineno = p->lineno;
- c->filename_index = p->current_filename_index;
- return c;
-}
-#define cons(a,b) cons_gen(p,(a),(b))
-
-static node*
-list1_gen(parser_state *p, node *a)
-{
- return cons(a, 0);
-}
-#define list1(a) list1_gen(p, (a))
-
-static node*
-list2_gen(parser_state *p, node *a, node *b)
-{
- return cons(a, cons(b,0));
-}
-#define list2(a,b) list2_gen(p, (a),(b))
-
-static node*
-list3_gen(parser_state *p, node *a, node *b, node *c)
-{
- return cons(a, cons(b, cons(c,0)));
-}
-#define list3(a,b,c) list3_gen(p, (a),(b),(c))
-
-static node*
-list4_gen(parser_state *p, node *a, node *b, node *c, node *d)
-{
- return cons(a, cons(b, cons(c, cons(d, 0))));
-}
-#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d))
-
-static node*
-list5_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e)
-{
- return cons(a, cons(b, cons(c, cons(d, cons(e, 0)))));
-}
-#define list5(a,b,c,d,e) list5_gen(p, (a),(b),(c),(d),(e))
-
-static node*
-list6_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e, node *f)
-{
- return cons(a, cons(b, cons(c, cons(d, cons(e, cons(f, 0))))));
-}
-#define list6(a,b,c,d,e,f) list6_gen(p, (a),(b),(c),(d),(e),(f))
-
-static node*
-append_gen(parser_state *p, node *a, node *b)
-{
- node *c = a;
-
- if (!a) return b;
- while (c->cdr) {
- c = c->cdr;
- }
- if (b) {
- c->cdr = b;
- }
- return a;
-}
-#define append(a,b) append_gen(p,(a),(b))
-#define push(a,b) append_gen(p,(a),list1(b))
-
-static char*
-parser_strndup(parser_state *p, const char *s, size_t len)
-{
- char *b = (char *)parser_palloc(p, len+1);
-
- memcpy(b, s, len);
- b[len] = '\0';
- return b;
-}
-#define strndup(s,len) parser_strndup(p, s, len)
-
-static char*
-parser_strdup(parser_state *p, const char *s)
-{
- return parser_strndup(p, s, strlen(s));
-}
-#undef strdup
-#define strdup(s) parser_strdup(p, s)
-
-/* xxx ----------------------------- */
-
-static node*
-local_switch(parser_state *p)
-{
- node *prev = p->locals;
-
- p->locals = cons(0, 0);
- return prev;
-}
-
-static void
-local_resume(parser_state *p, node *prev)
-{
- p->locals = prev;
-}
-
-static void
-local_nest(parser_state *p)
-{
- p->locals = cons(0, p->locals);
-}
-
-static void
-local_unnest(parser_state *p)
-{
- p->locals = p->locals->cdr;
-}
-
-static int
-local_var_p(parser_state *p, mrb_sym sym)
-{
- node *l = p->locals;
-
- while (l) {
- node *n = l->car;
- while (n) {
- if (sym(n->car) == sym) return 1;
- n = n->cdr;
- }
- l = l->cdr;
- }
- return 0;
-}
-
-static void
-local_add_f(parser_state *p, mrb_sym sym)
-{
- if (p->locals->car && !p->locals->car->car) {
- p->locals->car->car = nsym(sym);
- } else {
- p->locals->car = push(p->locals->car, nsym(sym));
- }
-}
-
-static void
-local_add(parser_state *p, mrb_sym sym)
-{
- if (!local_var_p(p, sym)) {
- local_add_f(p, sym);
- }
-}
-
-/* (:scope (vars..) (prog...)) */
-static node*
-new_scope(parser_state *p, node *body)
-{
- return cons((node*)NODE_SCOPE, cons(p->locals->car, body));
-}
-
-/* (:begin prog...) */
-static node*
-new_begin(parser_state *p, node *body)
-{
- if (body)
- return list2((node*)NODE_BEGIN, body);
- return cons((node*)NODE_BEGIN, 0);
-}
-
-#define newline_node(n) (n)
-
-/* (:rescue body rescue else) */
-static node*
-new_rescue(parser_state *p, node *body, node *resq, node *els)
-{
- return list4((node*)NODE_RESCUE, body, resq, els);
-}
-
-/* (:ensure body ensure) */
-static node*
-new_ensure(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_ENSURE, cons(a, cons(0, b)));
-}
-
-/* (:nil) */
-static node*
-new_nil(parser_state *p)
-{
- return list1((node*)NODE_NIL);
-}
-
-/* (:true) */
-static node*
-new_true(parser_state *p)
-{
- return list1((node*)NODE_TRUE);
-}
-
-/* (:false) */
-static node*
-new_false(parser_state *p)
-{
- return list1((node*)NODE_FALSE);
-}
-
-/* (:alias new old) */
-static node*
-new_alias(parser_state *p, mrb_sym a, mrb_sym b)
-{
- return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b)));
-}
-
-/* (:if cond then else) */
-static node*
-new_if(parser_state *p, node *a, node *b, node *c)
-{
- return list4((node*)NODE_IF, a, b, c);
-}
-
-/* (:unless cond then else) */
-static node*
-new_unless(parser_state *p, node *a, node *b, node *c)
-{
- return list4((node*)NODE_IF, a, c, b);
-}
-
-/* (:while cond body) */
-static node*
-new_while(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_WHILE, cons(a, b));
-}
-
-/* (:until cond body) */
-static node*
-new_until(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_UNTIL, cons(a, b));
-}
-
-/* (:for var obj body) */
-static node*
-new_for(parser_state *p, node *v, node *o, node *b)
-{
- return list4((node*)NODE_FOR, v, o, b);
-}
-
-/* (:case a ((when ...) body) ((when...) body)) */
-static node*
-new_case(parser_state *p, node *a, node *b)
-{
- node *n = list2((node*)NODE_CASE, a);
- node *n2 = n;
-
- while (n2->cdr) {
- n2 = n2->cdr;
- }
- n2->cdr = b;
- return n;
-}
-
-/* (:postexe a) */
-static node*
-new_postexe(parser_state *p, node *a)
-{
- return cons((node*)NODE_POSTEXE, a);
-}
-
-/* (:self) */
-static node*
-new_self(parser_state *p)
-{
- return list1((node*)NODE_SELF);
-}
-
-/* (:call a b c) */
-static node*
-new_call(parser_state *p, node *a, mrb_sym b, node *c)
-{
- return list4((node*)NODE_CALL, a, nsym(b), c);
-}
-
-/* (:fcall self mid args) */
-static node*
-new_fcall(parser_state *p, mrb_sym b, node *c)
-{
- return list4((node*)NODE_FCALL, new_self(p), nsym(b), c);
-}
-
-/* (:super . c) */
-static node*
-new_super(parser_state *p, node *c)
-{
- return cons((node*)NODE_SUPER, c);
-}
-
-/* (:zsuper) */
-static node*
-new_zsuper(parser_state *p)
-{
- return list1((node*)NODE_ZSUPER);
-}
-
-/* (:yield . c) */
-static node*
-new_yield(parser_state *p, node *c)
-{
- if (c) {
- if (c->cdr) {
- yyerror(p, "both block arg and actual block given");
- }
- return cons((node*)NODE_YIELD, c->car);
- }
- return cons((node*)NODE_YIELD, 0);
-}
-
-/* (:return . c) */
-static node*
-new_return(parser_state *p, node *c)
-{
- return cons((node*)NODE_RETURN, c);
-}
-
-/* (:break . c) */
-static node*
-new_break(parser_state *p, node *c)
-{
- return cons((node*)NODE_BREAK, c);
-}
-
-/* (:next . c) */
-static node*
-new_next(parser_state *p, node *c)
-{
- return cons((node*)NODE_NEXT, c);
-}
-
-/* (:redo) */
-static node*
-new_redo(parser_state *p)
-{
- return list1((node*)NODE_REDO);
-}
-
-/* (:retry) */
-static node*
-new_retry(parser_state *p)
-{
- return list1((node*)NODE_RETRY);
-}
-
-/* (:dot2 a b) */
-static node*
-new_dot2(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_DOT2, cons(a, b));
-}
-
-/* (:dot3 a b) */
-static node*
-new_dot3(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_DOT3, cons(a, b));
-}
-
-/* (:colon2 b c) */
-static node*
-new_colon2(parser_state *p, node *b, mrb_sym c)
-{
- return cons((node*)NODE_COLON2, cons(b, nsym(c)));
-}
-
-/* (:colon3 . c) */
-static node*
-new_colon3(parser_state *p, mrb_sym c)
-{
- return cons((node*)NODE_COLON3, nsym(c));
-}
-
-/* (:and a b) */
-static node*
-new_and(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_AND, cons(a, b));
-}
-
-/* (:or a b) */
-static node*
-new_or(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_OR, cons(a, b));
-}
-
-/* (:array a...) */
-static node*
-new_array(parser_state *p, node *a)
-{
- return cons((node*)NODE_ARRAY, a);
-}
-
-/* (:splat . a) */
-static node*
-new_splat(parser_state *p, node *a)
-{
- return cons((node*)NODE_SPLAT, a);
-}
-
-/* (:hash (k . v) (k . v)...) */
-static node*
-new_hash(parser_state *p, node *a)
-{
- return cons((node*)NODE_HASH, a);
-}
-
-/* (:sym . a) */
-static node*
-new_sym(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_SYM, nsym(sym));
-}
-
-static mrb_sym
-new_strsym(parser_state *p, node* str)
-{
- const char *s = (const char*)str->cdr->car;
- size_t len = (size_t)str->cdr->cdr;
-
- return mrb_intern(p->mrb, s, len);
-}
-
-/* (:lvar . a) */
-static node*
-new_lvar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_LVAR, nsym(sym));
-}
-
-/* (:gvar . a) */
-static node*
-new_gvar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_GVAR, nsym(sym));
-}
-
-/* (:ivar . a) */
-static node*
-new_ivar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_IVAR, nsym(sym));
-}
-
-/* (:cvar . a) */
-static node*
-new_cvar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_CVAR, nsym(sym));
-}
-
-/* (:const . a) */
-static node*
-new_const(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_CONST, nsym(sym));
-}
-
-/* (:undef a...) */
-static node*
-new_undef(parser_state *p, mrb_sym sym)
-{
- return list2((node*)NODE_UNDEF, nsym(sym));
-}
-
-/* (:class class super body) */
-static node*
-new_class(parser_state *p, node *c, node *s, node *b)
-{
- return list4((node*)NODE_CLASS, c, s, cons(p->locals->car, b));
-}
-
-/* (:sclass obj body) */
-static node*
-new_sclass(parser_state *p, node *o, node *b)
-{
- return list3((node*)NODE_SCLASS, o, cons(p->locals->car, b));
-}
-
-/* (:module module body) */
-static node*
-new_module(parser_state *p, node *m, node *b)
-{
- return list3((node*)NODE_MODULE, m, cons(p->locals->car, b));
-}
-
-/* (:def m lv (arg . body)) */
-static node*
-new_def(parser_state *p, mrb_sym m, node *a, node *b)
-{
- return list5((node*)NODE_DEF, nsym(m), p->locals->car, a, b);
-}
-
-/* (:sdef obj m lv (arg . body)) */
-static node*
-new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b)
-{
- return list6((node*)NODE_SDEF, o, nsym(m), p->locals->car, a, b);
-}
-
-/* (:arg . sym) */
-static node*
-new_arg(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_ARG, nsym(sym));
-}
-
-/* (m o r m2 b) */
-/* m: (a b c) */
-/* o: ((a . e1) (b . e2)) */
-/* r: a */
-/* m2: (a b c) */
-/* b: a */
-static node*
-new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
-{
- node *n;
-
- n = cons(m2, nsym(blk));
- n = cons(nsym(rest), n);
- n = cons(opt, n);
- return cons(m, n);
-}
-
-/* (:block_arg . a) */
-static node*
-new_block_arg(parser_state *p, node *a)
-{
- return cons((node*)NODE_BLOCK_ARG, a);
-}
-
-/* (:block arg body) */
-static node*
-new_block(parser_state *p, node *a, node *b)
-{
- return list4((node*)NODE_BLOCK, p->locals->car, a, b);
-}
-
-/* (:lambda arg body) */
-static node*
-new_lambda(parser_state *p, node *a, node *b)
-{
- return list4((node*)NODE_LAMBDA, p->locals->car, a, b);
-}
-
-/* (:asgn lhs rhs) */
-static node*
-new_asgn(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_ASGN, cons(a, b));
-}
-
-/* (:masgn mlhs=(pre rest post) mrhs) */
-static node*
-new_masgn(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_MASGN, cons(a, b));
-}
-
-/* (:asgn lhs rhs) */
-static node*
-new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
-{
- return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
-}
-
-/* (:int . i) */
-static node*
-new_int(parser_state *p, const char *s, int base)
-{
- return list3((node*)NODE_INT, (node*)strdup(s), (node*)(intptr_t)base);
-}
-
-/* (:float . i) */
-static node*
-new_float(parser_state *p, const char *s)
-{
- return cons((node*)NODE_FLOAT, (node*)strdup(s));
-}
-
-/* (:str . (s . len)) */
-static node*
-new_str(parser_state *p, const char *s, int len)
-{
- return cons((node*)NODE_STR, cons((node*)strndup(s, len), (node*)(intptr_t)len));
-}
-
-/* (:dstr . a) */
-static node*
-new_dstr(parser_state *p, node *a)
-{
- return cons((node*)NODE_DSTR, a);
-}
-
-/* (:str . (s . len)) */
-static node*
-new_xstr(parser_state *p, const char *s, int len)
-{
- return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len));
-}
-
-/* (:xstr . a) */
-static node*
-new_dxstr(parser_state *p, node *a)
-{
- return cons((node*)NODE_DXSTR, a);
-}
-
-/* (:dsym . a) */
-static node*
-new_dsym(parser_state *p, node *a)
-{
- return cons((node*)NODE_DSYM, new_dstr(p, a));
-}
-
-/* (:str . (a . a)) */
-static node*
-new_regx(parser_state *p, const char *p1, const char* p2)
-{
- return cons((node*)NODE_REGX, cons((node*)p1, (node*)p2));
-}
-
-/* (:dregx . a) */
-static node*
-new_dregx(parser_state *p, node *a, node *b)
-{
- return cons((node*)NODE_DREGX, cons(a, b));
-}
-
-/* (:backref . n) */
-static node*
-new_back_ref(parser_state *p, int n)
-{
- return cons((node*)NODE_BACK_REF, (node*)(intptr_t)n);
-}
-
-/* (:nthref . n) */
-static node*
-new_nth_ref(parser_state *p, int n)
-{
- return cons((node*)NODE_NTH_REF, (node*)(intptr_t)n);
-}
-
-/* (:heredoc . a) */
-static node*
-new_heredoc(parser_state *p)
-{
- parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info));
- return cons((node*)NODE_HEREDOC, (node*)inf);
-}
-
-static void
-new_bv(parser_state *p, mrb_sym id)
-{
-}
-
-static node*
-new_literal_delim(parser_state *p)
-{
- return cons((node*)NODE_LITERAL_DELIM, 0);
-}
-
-/* (:words . a) */
-static node*
-new_words(parser_state *p, node *a)
-{
- return cons((node*)NODE_WORDS, a);
-}
-
-/* (:symbols . a) */
-static node*
-new_symbols(parser_state *p, node *a)
-{
- return cons((node*)NODE_SYMBOLS, a);
-}
-
-/* xxx ----------------------------- */
-
-/* (:call a op) */
-static node*
-call_uni_op(parser_state *p, node *recv, const char *m)
-{
- return new_call(p, recv, intern_cstr(m), 0);
-}
-
-/* (:call a op b) */
-static node*
-call_bin_op(parser_state *p, node *recv, const char *m, node *arg1)
-{
- return new_call(p, recv, intern_cstr(m), list1(list1(arg1)));
-}
-
-static void
-args_with_block(parser_state *p, node *a, node *b)
-{
- if (b) {
- if (a->cdr) {
- yyerror(p, "both block arg and actual block given");
- }
- a->cdr = b;
- }
-}
-
-static void
-call_with_block(parser_state *p, node *a, node *b)
-{
- node *n;
-
- if (a->car == (node*)NODE_SUPER ||
- a->car == (node*)NODE_ZSUPER) {
- if (!a->cdr) a->cdr = cons(0, b);
- else {
- args_with_block(p, a->cdr, b);
- }
- }
- else {
- n = a->cdr->cdr->cdr;
- if (!n->car) n->car = cons(0, b);
- else {
- args_with_block(p, n->car, b);
- }
- }
-}
-
-static node*
-negate_lit(parser_state *p, node *n)
-{
- return cons((node*)NODE_NEGATE, n);
-}
-
-static node*
-cond(node *n)
-{
- return n;
-}
-
-static node*
-ret_args(parser_state *p, node *n)
-{
- if (n->cdr) {
- yyerror(p, "block argument should not be given");
- return NULL;
- }
- if (!n->car->cdr) return n->car->car;
- return new_array(p, n->car);
-}
-
-static void
-assignable(parser_state *p, node *lhs)
-{
- if ((int)(intptr_t)lhs->car == NODE_LVAR) {
- local_add(p, sym(lhs->cdr));
- }
-}
-
-static node*
-var_reference(parser_state *p, node *lhs)
-{
- node *n;
-
- if ((int)(intptr_t)lhs->car == NODE_LVAR) {
- if (!local_var_p(p, sym(lhs->cdr))) {
- n = new_fcall(p, sym(lhs->cdr), 0);
- cons_free(lhs);
- return n;
- }
- }
-
- return lhs;
-}
-
-typedef enum mrb_string_type string_type;
-
-static node*
-new_strterm(parser_state *p, string_type type, int term, int paren)
-{
- return cons((node*)(intptr_t)type, cons((node*)0, cons((node*)(intptr_t)paren, (node*)(intptr_t)term)));
-}
-
-static void
-end_strterm(parser_state *p)
-{
- cons_free(p->lex_strterm->cdr->cdr);
- cons_free(p->lex_strterm->cdr);
- cons_free(p->lex_strterm);
- p->lex_strterm = NULL;
-}
-
-static parser_heredoc_info *
-parsing_heredoc_inf(parser_state *p)
-{
- node *nd = p->parsing_heredoc;
- if (nd == NULL)
- return NULL;
- /* mrb_assert(nd->car->car == NODE_HEREDOC); */
- return (parser_heredoc_info*)nd->car->cdr;
-}
-
-static void
-heredoc_treat_nextline(parser_state *p)
-{
- if (p->heredocs_from_nextline == NULL)
- return;
- if (p->parsing_heredoc == NULL) {
- node *n;
- p->parsing_heredoc = p->heredocs_from_nextline;
- p->lex_strterm_before_heredoc = p->lex_strterm;
- p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0);
- n = p->all_heredocs;
- if (n) {
- while (n->cdr)
- n = n->cdr;
- n->cdr = p->parsing_heredoc;
- }
- else {
- p->all_heredocs = p->parsing_heredoc;
- }
- }
- else {
- node *n, *m;
- m = p->heredocs_from_nextline;
- while (m->cdr)
- m = m->cdr;
- n = p->all_heredocs;
- mrb_assert(n != NULL);
- if (n == p->parsing_heredoc) {
- m->cdr = n;
- p->all_heredocs = p->heredocs_from_nextline;
- p->parsing_heredoc = p->heredocs_from_nextline;
- }
- else {
- while (n->cdr != p->parsing_heredoc) {
- n = n->cdr;
- mrb_assert(n != NULL);
- }
- m->cdr = n->cdr;
- n->cdr = p->heredocs_from_nextline;
- p->parsing_heredoc = p->heredocs_from_nextline;
- }
- }
- p->heredocs_from_nextline = NULL;
-}
-
-static void
-heredoc_end(parser_state *p)
-{
- p->parsing_heredoc = p->parsing_heredoc->cdr;
- if (p->parsing_heredoc == NULL) {
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- end_strterm(p);
- p->lex_strterm = p->lex_strterm_before_heredoc;
- p->lex_strterm_before_heredoc = NULL;
- p->heredoc_end_now = TRUE;
- }
- else {
- /* next heredoc */
- p->lex_strterm->car = (node*)(intptr_t)parsing_heredoc_inf(p)->type;
- }
-}
-#define is_strterm_type(p,str_func) ((int)(intptr_t)((p)->lex_strterm->car) & (str_func))
-
-/* xxx ----------------------------- */
-
-%}
-
-%pure-parser
-%parse-param {parser_state *p}
-%lex-param {parser_state *p}
-
-%union {
- node *nd;
- mrb_sym id;
- int num;
- stack_type stack;
- const struct vtable *vars;
-}
-
-%token
- keyword_class
- keyword_module
- keyword_def
- keyword_undef
- keyword_begin
- keyword_rescue
- keyword_ensure
- keyword_end
- keyword_if
- keyword_unless
- keyword_then
- keyword_elsif
- keyword_else
- keyword_case
- keyword_when
- keyword_while
- keyword_until
- keyword_for
- keyword_break
- keyword_next
- keyword_redo
- keyword_retry
- keyword_in
- keyword_do
- keyword_do_cond
- keyword_do_block
- keyword_do_LAMBDA
- keyword_return
- keyword_yield
- keyword_super
- keyword_self
- keyword_nil
- keyword_true
- keyword_false
- keyword_and
- keyword_or
- keyword_not
- modifier_if
- modifier_unless
- modifier_while
- modifier_until
- modifier_rescue
- keyword_alias
- keyword_BEGIN
- keyword_END
- keyword__LINE__
- keyword__FILE__
- keyword__ENCODING__
-
-%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
-%token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
-%token <nd> tSTRING tSTRING_PART tSTRING_MID
-%token <nd> tNTH_REF tBACK_REF
-%token <num> tREGEXP_END
-
-%type <nd> singleton string string_rep string_interp xstring regexp
-%type <nd> literal numeric cpath symbol
-%type <nd> top_compstmt top_stmts top_stmt
-%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
-%type <nd> expr_value arg_value primary_value
-%type <nd> if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure
-%type <nd> args call_args opt_call_args
-%type <nd> paren_args opt_paren_args variable
-%type <nd> command_args aref_args opt_block_arg block_arg var_ref var_lhs
-%type <nd> command_asgn mrhs superclass block_call block_command
-%type <nd> f_block_optarg f_block_opt
-%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs
-%type <nd> assoc_list assocs assoc undef_list backref for_var
-%type <nd> block_param opt_block_param block_param_def f_opt
-%type <nd> bv_decls opt_bv_decl bvar f_larglist lambda_body
-%type <nd> brace_block cmd_brace_block do_block lhs none f_bad_arg
-%type <nd> mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner
-%type <id> fsym sym basic_symbol operation operation2 operation3
-%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn
-%type <nd> heredoc words symbols
-
-%token tUPLUS /* unary+ */
-%token tUMINUS /* unary- */
-%token tPOW /* ** */
-%token tCMP /* <=> */
-%token tEQ /* == */
-%token tEQQ /* === */
-%token tNEQ /* != */
-%token tGEQ /* >= */
-%token tLEQ /* <= */
-%token tANDOP tOROP /* && and || */
-%token tMATCH tNMATCH /* =~ and !~ */
-%token tDOT2 tDOT3 /* .. and ... */
-%token tAREF tASET /* [] and []= */
-%token tLSHFT tRSHFT /* << and >> */
-%token tCOLON2 /* :: */
-%token tCOLON3 /* :: at EXPR_BEG */
-%token <id> tOP_ASGN /* +=, -= etc. */
-%token tASSOC /* => */
-%token tLPAREN /* ( */
-%token tLPAREN_ARG /* ( */
-%token tRPAREN /* ) */
-%token tLBRACK /* [ */
-%token tLBRACE /* { */
-%token tLBRACE_ARG /* { */
-%token tSTAR /* * */
-%token tAMPER /* & */
-%token tLAMBDA /* -> */
-%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
-%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
-%token <nd> tHEREDOC_BEG /* <<, <<- */
-%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM
-%token <nd> tHD_STRING_PART tHD_STRING_MID
-
-/*
- * precedence table
- */
-
-%nonassoc tLOWEST
-%nonassoc tLBRACE_ARG
-
-%nonassoc modifier_if modifier_unless modifier_while modifier_until
-%left keyword_or keyword_and
-%right keyword_not
-%right '=' tOP_ASGN
-%left modifier_rescue
-%right '?' ':'
-%nonassoc tDOT2 tDOT3
-%left tOROP
-%left tANDOP
-%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
-%left '>' tGEQ '<' tLEQ
-%left '|' '^'
-%left '&'
-%left tLSHFT tRSHFT
-%left '+' '-'
-%left '*' '/' '%'
-%right tUMINUS_NUM tUMINUS
-%right tPOW
-%right '!' '~' tUPLUS
-
-%nonassoc idNULL
-%nonassoc idRespond_to
-%nonassoc idIFUNC
-%nonassoc idCFUNC
-%nonassoc id_core_set_method_alias
-%nonassoc id_core_set_variable_alias
-%nonassoc id_core_undef_method
-%nonassoc id_core_define_method
-%nonassoc id_core_define_singleton_method
-%nonassoc id_core_set_postexe
-
-%token tLAST_TOKEN
-
-%%
-program : {
- p->lstate = EXPR_BEG;
- if (!p->locals) p->locals = cons(0,0);
- }
- top_compstmt
- {
- p->tree = new_scope(p, $2);
- }
- ;
-
-top_compstmt : top_stmts opt_terms
- {
- $$ = $1;
- }
- ;
-
-top_stmts : none
- {
- $$ = new_begin(p, 0);
- }
- | top_stmt
- {
- $$ = new_begin(p, $1);
- }
- | top_stmts terms top_stmt
- {
- $$ = push($1, newline_node($3));
- }
- | error top_stmt
- {
- $$ = new_begin(p, 0);
- }
- ;
-
-top_stmt : stmt
- | keyword_BEGIN
- {
- $<nd>$ = local_switch(p);
- }
- '{' top_compstmt '}'
- {
- yyerror(p, "BEGIN not supported");
- local_resume(p, $<nd>2);
- $$ = 0;
- }
- ;
-
-bodystmt : compstmt
- opt_rescue
- opt_else
- opt_ensure
- {
- if ($2) {
- $$ = new_rescue(p, $1, $2, $3);
- }
- else if ($3) {
- yywarn(p, "else without rescue is useless");
- $$ = push($1, $3);
- }
- else {
- $$ = $1;
- }
- if ($4) {
- if ($$) {
- $$ = new_ensure(p, $$, $4);
- }
- else {
- $$ = push($4, new_nil(p));
- }
- }
- }
- ;
-
-compstmt : stmts opt_terms
- {
- $$ = $1;
- }
- ;
-
-stmts : none
- {
- $$ = new_begin(p, 0);
- }
- | stmt
- {
- $$ = new_begin(p, $1);
- }
- | stmts terms stmt
- {
- $$ = push($1, newline_node($3));
- }
- | error stmt
- {
- $$ = new_begin(p, $2);
- }
- ;
-
-stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
- {
- $$ = new_alias(p, $2, $4);
- }
- | keyword_undef undef_list
- {
- $$ = $2;
- }
- | stmt modifier_if expr_value
- {
- $$ = new_if(p, cond($3), $1, 0);
- }
- | stmt modifier_unless expr_value
- {
- $$ = new_unless(p, cond($3), $1, 0);
- }
- | stmt modifier_while expr_value
- {
- $$ = new_while(p, cond($3), $1);
- }
- | stmt modifier_until expr_value
- {
- $$ = new_until(p, cond($3), $1);
- }
- | stmt modifier_rescue stmt
- {
- $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0);
- }
- | keyword_END '{' compstmt '}'
- {
- yyerror(p, "END not suported");
- $$ = new_postexe(p, $3);
- }
- | command_asgn
- | mlhs '=' command_call
- {
- $$ = new_masgn(p, $1, $3);
- }
- | var_lhs tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, $1, $2, $3);
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6);
- }
- | primary_value '.' tIDENTIFIER tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value '.' tCONSTANT tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call
- {
- yyerror(p, "constant re-assignment");
- $$ = 0;
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | backref tOP_ASGN command_call
- {
- backref_error(p, $1);
- $$ = new_begin(p, 0);
- }
- | lhs '=' mrhs
- {
- $$ = new_asgn(p, $1, new_array(p, $3));
- }
- | mlhs '=' arg_value
- {
- $$ = new_masgn(p, $1, $3);
- }
- | mlhs '=' mrhs
- {
- $$ = new_masgn(p, $1, new_array(p, $3));
- }
- | expr
- ;
-
-command_asgn : lhs '=' command_call
- {
- $$ = new_asgn(p, $1, $3);
- }
- | lhs '=' command_asgn
- {
- $$ = new_asgn(p, $1, $3);
- }
- ;
-
-
-expr : command_call
- | expr keyword_and expr
- {
- $$ = new_and(p, $1, $3);
- }
- | expr keyword_or expr
- {
- $$ = new_or(p, $1, $3);
- }
- | keyword_not opt_nl expr
- {
- $$ = call_uni_op(p, cond($3), "!");
- }
- | '!' command_call
- {
- $$ = call_uni_op(p, cond($2), "!");
- }
- | arg
- ;
-
-expr_value : expr
- {
- if (!$1) $$ = new_nil(p);
- else $$ = $1;
- }
- ;
-
-command_call : command
- | block_command
- ;
-
-block_command : block_call
- | block_call dot_or_colon operation2 command_args
- ;
-
-cmd_brace_block : tLBRACE_ARG
- {
- local_nest(p);
- }
- opt_block_param
- compstmt
- '}'
- {
- $$ = new_block(p, $3, $4);
- local_unnest(p);
- }
- ;
-
-command : operation command_args %prec tLOWEST
- {
- $$ = new_fcall(p, $1, $2);
- }
- | operation command_args cmd_brace_block
- {
- args_with_block(p, $2, $3);
- $$ = new_fcall(p, $1, $2);
- }
- | primary_value '.' operation2 command_args %prec tLOWEST
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value '.' operation2 command_args cmd_brace_block
- {
- args_with_block(p, $4, $5);
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 command_args %prec tLOWEST
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 command_args cmd_brace_block
- {
- args_with_block(p, $4, $5);
- $$ = new_call(p, $1, $3, $4);
- }
- | keyword_super command_args
- {
- $$ = new_super(p, $2);
- }
- | keyword_yield command_args
- {
- $$ = new_yield(p, $2);
- }
- | keyword_return call_args
- {
- $$ = new_return(p, ret_args(p, $2));
- }
- | keyword_break call_args
- {
- $$ = new_break(p, ret_args(p, $2));
- }
- | keyword_next call_args
- {
- $$ = new_next(p, ret_args(p, $2));
- }
- ;
-
-mlhs : mlhs_basic
- {
- $$ = $1;
- }
- | tLPAREN mlhs_inner rparen
- {
- $$ = $2;
- }
- ;
-
-mlhs_inner : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- $$ = list1($2);
- }
- ;
-
-mlhs_basic : mlhs_list
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item
- {
- $$ = list1(push($1,$2));
- }
- | mlhs_list tSTAR mlhs_node
- {
- $$ = list2($1, $3);
- }
- | mlhs_list tSTAR mlhs_node ',' mlhs_post
- {
- $$ = list3($1, $3, $5);
- }
- | mlhs_list tSTAR
- {
- $$ = list2($1, new_nil(p));
- }
- | mlhs_list tSTAR ',' mlhs_post
- {
- $$ = list3($1, new_nil(p), $4);
- }
- | tSTAR mlhs_node
- {
- $$ = list2(0, $2);
- }
- | tSTAR mlhs_node ',' mlhs_post
- {
- $$ = list3(0, $2, $4);
- }
- | tSTAR
- {
- $$ = list2(0, new_nil(p));
- }
- | tSTAR ',' mlhs_post
- {
- $$ = list3(0, new_nil(p), $3);
- }
- ;
-
-mlhs_item : mlhs_node
- | tLPAREN mlhs_inner rparen
- {
- $$ = $2;
- }
- ;
-
-mlhs_list : mlhs_item ','
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item ','
- {
- $$ = push($1, $2);
- }
- ;
-
-mlhs_post : mlhs_item
- {
- $$ = list1($1);
- }
- | mlhs_list mlhs_item
- {
- $$ = push($1, $2);
- }
- ;
-
-mlhs_node : variable
- {
- assignable(p, $1);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern("[]",2), $3);
- }
- | primary_value '.' tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' tCONSTANT
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon3(p, $2);
- }
- | backref
- {
- backref_error(p, $1);
- $$ = 0;
- }
- ;
-
-lhs : variable
- {
- assignable(p, $1);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern("[]",2), $3);
- }
- | primary_value '.' tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' tCONSTANT
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value tCOLON2 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- if (p->in_def || p->in_single)
- yyerror(p, "dynamic constant assignment");
- $$ = new_colon3(p, $2);
- }
- | backref
- {
- backref_error(p, $1);
- $$ = 0;
- }
- ;
-
-cname : tIDENTIFIER
- {
- yyerror(p, "class/module name must be CONSTANT");
- }
- | tCONSTANT
- ;
-
-cpath : tCOLON3 cname
- {
- $$ = cons((node*)1, nsym($2));
- }
- | cname
- {
- $$ = cons((node*)0, nsym($1));
- }
- | primary_value tCOLON2 cname
- {
- $$ = cons($1, nsym($3));
- }
- ;
-
-fname : tIDENTIFIER
- | tCONSTANT
- | tFID
- | op
- {
- p->lstate = EXPR_ENDFN;
- $$ = $1;
- }
- | reswords
- {
- p->lstate = EXPR_ENDFN;
- $$ = $<id>1;
- }
- ;
-
-fsym : fname
- | basic_symbol
- ;
-
-undef_list : fsym
- {
- $$ = new_undef(p, $1);
- }
- | undef_list ',' {p->lstate = EXPR_FNAME;} fsym
- {
- $$ = push($1, nsym($4));
- }
- ;
-
-op : '|' { $$ = intern_c('|'); }
- | '^' { $$ = intern_c('^'); }
- | '&' { $$ = intern_c('&'); }
- | tCMP { $$ = intern("<=>",3); }
- | tEQ { $$ = intern("==",2); }
- | tEQQ { $$ = intern("===",3); }
- | tMATCH { $$ = intern("=~",2); }
- | tNMATCH { $$ = intern("!~",2); }
- | '>' { $$ = intern_c('>'); }
- | tGEQ { $$ = intern(">=",2); }
- | '<' { $$ = intern_c('<'); }
- | tLEQ { $$ = intern("<=",2); }
- | tNEQ { $$ = intern("!=",2); }
- | tLSHFT { $$ = intern("<<",2); }
- | tRSHFT { $$ = intern(">>",2); }
- | '+' { $$ = intern_c('+'); }
- | '-' { $$ = intern_c('-'); }
- | '*' { $$ = intern_c('*'); }
- | tSTAR { $$ = intern_c('*'); }
- | '/' { $$ = intern_c('/'); }
- | '%' { $$ = intern_c('%'); }
- | tPOW { $$ = intern("**",2); }
- | '!' { $$ = intern_c('!'); }
- | '~' { $$ = intern_c('~'); }
- | tUPLUS { $$ = intern("+@",2); }
- | tUMINUS { $$ = intern("-@",2); }
- | tAREF { $$ = intern("[]",2); }
- | tASET { $$ = intern("[]=",3); }
- | '`' { $$ = intern_c('`'); }
- ;
-
-reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
- | keyword_BEGIN | keyword_END
- | keyword_alias | keyword_and | keyword_begin
- | keyword_break | keyword_case | keyword_class | keyword_def
- | keyword_do | keyword_else | keyword_elsif
- | keyword_end | keyword_ensure | keyword_false
- | keyword_for | keyword_in | keyword_module | keyword_next
- | keyword_nil | keyword_not | keyword_or | keyword_redo
- | keyword_rescue | keyword_retry | keyword_return | keyword_self
- | keyword_super | keyword_then | keyword_true | keyword_undef
- | keyword_when | keyword_yield | keyword_if | keyword_unless
- | keyword_while | keyword_until
- ;
-
-arg : lhs '=' arg
- {
- $$ = new_asgn(p, $1, $3);
- }
- | lhs '=' arg modifier_rescue arg
- {
- $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
- }
- | var_lhs tOP_ASGN arg
- {
- $$ = new_op_asgn(p, $1, $2, $3);
- }
- | var_lhs tOP_ASGN arg modifier_rescue arg
- {
- $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0));
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6);
- }
- | primary_value '.' tIDENTIFIER tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value '.' tCONSTANT tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg
- {
- $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5);
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN arg
- {
- yyerror(p, "constant re-assignment");
- $$ = new_begin(p, 0);
- }
- | tCOLON3 tCONSTANT tOP_ASGN arg
- {
- yyerror(p, "constant re-assignment");
- $$ = new_begin(p, 0);
- }
- | backref tOP_ASGN arg
- {
- backref_error(p, $1);
- $$ = new_begin(p, 0);
- }
- | arg tDOT2 arg
- {
- $$ = new_dot2(p, $1, $3);
- }
- | arg tDOT3 arg
- {
- $$ = new_dot3(p, $1, $3);
- }
- | arg '+' arg
- {
- $$ = call_bin_op(p, $1, "+", $3);
- }
- | arg '-' arg
- {
- $$ = call_bin_op(p, $1, "-", $3);
- }
- | arg '*' arg
- {
- $$ = call_bin_op(p, $1, "*", $3);
- }
- | arg '/' arg
- {
- $$ = call_bin_op(p, $1, "/", $3);
- }
- | arg '%' arg
- {
- $$ = call_bin_op(p, $1, "%", $3);
- }
- | arg tPOW arg
- {
- $$ = call_bin_op(p, $1, "**", $3);
- }
- | tUMINUS_NUM tINTEGER tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
- }
- | tUMINUS_NUM tFLOAT tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@");
- }
- | tUPLUS arg
- {
- $$ = call_uni_op(p, $2, "+@");
- }
- | tUMINUS arg
- {
- $$ = call_uni_op(p, $2, "-@");
- }
- | arg '|' arg
- {
- $$ = call_bin_op(p, $1, "|", $3);
- }
- | arg '^' arg
- {
- $$ = call_bin_op(p, $1, "^", $3);
- }
- | arg '&' arg
- {
- $$ = call_bin_op(p, $1, "&", $3);
- }
- | arg tCMP arg
- {
- $$ = call_bin_op(p, $1, "<=>", $3);
- }
- | arg '>' arg
- {
- $$ = call_bin_op(p, $1, ">", $3);
- }
- | arg tGEQ arg
- {
- $$ = call_bin_op(p, $1, ">=", $3);
- }
- | arg '<' arg
- {
- $$ = call_bin_op(p, $1, "<", $3);
- }
- | arg tLEQ arg
- {
- $$ = call_bin_op(p, $1, "<=", $3);
- }
- | arg tEQ arg
- {
- $$ = call_bin_op(p, $1, "==", $3);
- }
- | arg tEQQ arg
- {
- $$ = call_bin_op(p, $1, "===", $3);
- }
- | arg tNEQ arg
- {
- $$ = call_bin_op(p, $1, "!=", $3);
- }
- | arg tMATCH arg
- {
- $$ = call_bin_op(p, $1, "=~", $3);
- }
- | arg tNMATCH arg
- {
- $$ = call_bin_op(p, $1, "!~", $3);
- }
- | '!' arg
- {
- $$ = call_uni_op(p, cond($2), "!");
- }
- | '~' arg
- {
- $$ = call_uni_op(p, cond($2), "~");
- }
- | arg tLSHFT arg
- {
- $$ = call_bin_op(p, $1, "<<", $3);
- }
- | arg tRSHFT arg
- {
- $$ = call_bin_op(p, $1, ">>", $3);
- }
- | arg tANDOP arg
- {
- $$ = new_and(p, $1, $3);
- }
- | arg tOROP arg
- {
- $$ = new_or(p, $1, $3);
- }
- | arg '?' arg opt_nl ':' arg
- {
- $$ = new_if(p, cond($1), $3, $6);
- }
- | primary
- {
- $$ = $1;
- }
- ;
-
-arg_value : arg
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- ;
-
-aref_args : none
- | args trailer
- {
- $$ = $1;
- }
- | args ',' assocs trailer
- {
- $$ = push($1, new_hash(p, $3));
- }
- | assocs trailer
- {
- $$ = cons(new_hash(p, $1), 0);
- }
- ;
-
-paren_args : '(' opt_call_args rparen
- {
- $$ = $2;
- }
- ;
-
-opt_paren_args : none
- | paren_args
- ;
-
-opt_call_args : none
- | call_args
- | args ','
- {
- $$ = cons($1,0);
- }
- | args ',' assocs ','
- {
- $$ = cons(push($1, new_hash(p, $3)), 0);
- }
- | assocs ','
- {
- $$ = cons(list1(new_hash(p, $1)), 0);
- }
- ;
-
-call_args : command
- {
- $$ = cons(list1($1), 0);
- }
- | args opt_block_arg
- {
- $$ = cons($1, $2);
- }
- | assocs opt_block_arg
- {
- $$ = cons(list1(new_hash(p, $1)), $2);
- }
- | args ',' assocs opt_block_arg
- {
- $$ = cons(push($1, new_hash(p, $3)), $4);
- }
- | block_arg
- {
- $$ = cons(0, $1);
- }
- ;
-
-command_args : {
- $<stack>$ = p->cmdarg_stack;
- CMDARG_PUSH(1);
- }
- call_args
- {
- p->cmdarg_stack = $<stack>1;
- $$ = $2;
- }
- ;
-
-block_arg : tAMPER arg_value
- {
- $$ = new_block_arg(p, $2);
- }
- ;
-
-opt_block_arg : ',' block_arg
- {
- $$ = $2;
- }
- | none
- {
- $$ = 0;
- }
- ;
-
-args : arg_value
- {
- $$ = cons($1, 0);
- }
- | tSTAR arg_value
- {
- $$ = cons(new_splat(p, $2), 0);
- }
- | args ',' arg_value
- {
- $$ = push($1, $3);
- }
- | args ',' tSTAR arg_value
- {
- $$ = push($1, new_splat(p, $4));
- }
- | args ',' heredoc_bodies arg_value
- {
- $$ = push($1, $4);
- }
- | args ',' heredoc_bodies tSTAR arg_value
- {
- $$ = push($1, new_splat(p, $5));
- }
- ;
-
-mrhs : args ',' arg_value
- {
- $$ = push($1, $3);
- }
- | args ',' tSTAR arg_value
- {
- $$ = push($1, new_splat(p, $4));
- }
- | tSTAR arg_value
- {
- $$ = list1(new_splat(p, $2));
- }
- ;
-
-primary : literal
- | string
- | xstring
- | regexp
- | heredoc
- | var_ref
- | backref
- | tFID
- {
- $$ = new_fcall(p, $1, 0);
- }
- | keyword_begin
- {
- $<stack>1 = p->cmdarg_stack;
- p->cmdarg_stack = 0;
- }
- bodystmt
- keyword_end
- {
- p->cmdarg_stack = $<stack>1;
- $$ = $3;
- }
- | tLPAREN_ARG
- {
- $<stack>1 = p->cmdarg_stack;
- p->cmdarg_stack = 0;
- }
- expr {p->lstate = EXPR_ENDARG;} rparen
- {
- p->cmdarg_stack = $<stack>1;
- $$ = $3;
- }
- | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
- {
- $$ = 0;
- }
- | tLPAREN compstmt ')'
- {
- $$ = $2;
- }
- | primary_value tCOLON2 tCONSTANT
- {
- $$ = new_colon2(p, $1, $3);
- }
- | tCOLON3 tCONSTANT
- {
- $$ = new_colon3(p, $2);
- }
- | tLBRACK aref_args ']'
- {
- $$ = new_array(p, $2);
- }
- | tLBRACE assoc_list '}'
- {
- $$ = new_hash(p, $2);
- }
- | keyword_return
- {
- $$ = new_return(p, 0);
- }
- | keyword_yield '(' call_args rparen
- {
- $$ = new_yield(p, $3);
- }
- | keyword_yield '(' rparen
- {
- $$ = new_yield(p, 0);
- }
- | keyword_yield
- {
- $$ = new_yield(p, 0);
- }
- | keyword_not '(' expr rparen
- {
- $$ = call_uni_op(p, cond($3), "!");
- }
- | keyword_not '(' rparen
- {
- $$ = call_uni_op(p, new_nil(p), "!");
- }
- | operation brace_block
- {
- $$ = new_fcall(p, $1, cons(0, $2));
- }
- | method_call
- | method_call brace_block
- {
- call_with_block(p, $1, $2);
- $$ = $1;
- }
- | tLAMBDA
- {
- local_nest(p);
- $<num>$ = p->lpar_beg;
- p->lpar_beg = ++p->paren_nest;
- }
- f_larglist
- lambda_body
- {
- p->lpar_beg = $<num>2;
- $$ = new_lambda(p, $3, $4);
- local_unnest(p);
- }
- | keyword_if expr_value then
- compstmt
- if_tail
- keyword_end
- {
- $$ = new_if(p, cond($2), $4, $5);
- }
- | keyword_unless expr_value then
- compstmt
- opt_else
- keyword_end
- {
- $$ = new_unless(p, cond($2), $4, $5);
- }
- | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_while(p, cond($3), $6);
- }
- | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_until(p, cond($3), $6);
- }
- | keyword_case expr_value opt_terms
- case_body
- keyword_end
- {
- $$ = new_case(p, $2, $4);
- }
- | keyword_case opt_terms case_body keyword_end
- {
- $$ = new_case(p, 0, $3);
- }
- | keyword_for for_var keyword_in
- {COND_PUSH(1);}
- expr_value do
- {COND_POP();}
- compstmt
- keyword_end
- {
- $$ = new_for(p, $2, $5, $8);
- }
- | keyword_class
- {
- $<num>$ = p->lineno;
- }
- cpath superclass
- {
- if (p->in_def || p->in_single)
- yyerror(p, "class definition in method body");
- $<nd>$ = local_switch(p);
- }
- bodystmt
- keyword_end
- {
- $$ = new_class(p, $3, $4, $6);
- SET_LINENO($$, $<num>2);
- local_resume(p, $<nd>5);
- }
- | keyword_class
- {
- $<num>$ = p->lineno;
- }
- tLSHFT expr
- {
- $<num>$ = p->in_def;
- p->in_def = 0;
- }
- term
- {
- $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single);
- p->in_single = 0;
- }
- bodystmt
- keyword_end
- {
- $$ = new_sclass(p, $4, $8);
- SET_LINENO($$, $<num>2);
- local_resume(p, $<nd>7->car);
- p->in_def = $<num>5;
- p->in_single = (int)(intptr_t)$<nd>7->cdr;
- }
- | keyword_module
- {
- $<num>$ = p->lineno;
- }
- cpath
- {
- if (p->in_def || p->in_single)
- yyerror(p, "module definition in method body");
- $<nd>$ = local_switch(p);
- }
- bodystmt
- keyword_end
- {
- $$ = new_module(p, $3, $5);
- SET_LINENO($$, $<num>2);
- local_resume(p, $<nd>4);
- }
- | keyword_def fname
- {
- p->in_def++;
- $<nd>$ = local_switch(p);
- $<stack>1 = p->cmdarg_stack;
- p->cmdarg_stack = 0;
- }
- f_arglist
- bodystmt
- keyword_end
- {
- $$ = new_def(p, $2, $4, $5);
- local_resume(p, $<nd>3);
- p->in_def--;
- p->cmdarg_stack = $<stack>1;
- }
- | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname
- {
- p->in_single++;
- p->lstate = EXPR_ENDFN; /* force for args */
- $<nd>$ = local_switch(p);
- $<stack>1 = p->cmdarg_stack;
- p->cmdarg_stack = 0;
- }
- f_arglist
- bodystmt
- keyword_end
- {
- $$ = new_sdef(p, $2, $5, $7, $8);
- local_resume(p, $<nd>6);
- p->in_single--;
- p->cmdarg_stack = $<stack>1;
- }
- | keyword_break
- {
- $$ = new_break(p, 0);
- }
- | keyword_next
- {
- $$ = new_next(p, 0);
- }
- | keyword_redo
- {
- $$ = new_redo(p);
- }
- | keyword_retry
- {
- $$ = new_retry(p);
- }
- ;
-
-primary_value : primary
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- ;
-
-then : term
- | keyword_then
- | term keyword_then
- ;
-
-do : term
- | keyword_do_cond
- ;
-
-if_tail : opt_else
- | keyword_elsif expr_value then
- compstmt
- if_tail
- {
- $$ = new_if(p, cond($2), $4, $5);
- }
- ;
-
-opt_else : none
- | keyword_else compstmt
- {
- $$ = $2;
- }
- ;
-
-for_var : lhs
- {
- $$ = list1(list1($1));
- }
- | mlhs
- ;
-
-f_marg : f_norm_arg
- {
- $$ = new_arg(p, $1);
- }
- | tLPAREN f_margs rparen
- {
- $$ = new_masgn(p, $2, 0);
- }
- ;
-
-f_marg_list : f_marg
- {
- $$ = list1($1);
- }
- | f_marg_list ',' f_marg
- {
- $$ = push($1, $3);
- }
- ;
-
-f_margs : f_marg_list
- {
- $$ = list3($1,0,0);
- }
- | f_marg_list ',' tSTAR f_norm_arg
- {
- $$ = list3($1, new_arg(p, $4), 0);
- }
- | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
- {
- $$ = list3($1, new_arg(p, $4), $6);
- }
- | f_marg_list ',' tSTAR
- {
- $$ = list3($1, (node*)-1, 0);
- }
- | f_marg_list ',' tSTAR ',' f_marg_list
- {
- $$ = list3($1, (node*)-1, $5);
- }
- | tSTAR f_norm_arg
- {
- $$ = list3(0, new_arg(p, $2), 0);
- }
- | tSTAR f_norm_arg ',' f_marg_list
- {
- $$ = list3(0, new_arg(p, $2), $4);
- }
- | tSTAR
- {
- $$ = list3(0, (node*)-1, 0);
- }
- | tSTAR ',' f_marg_list
- {
- $$ = list3(0, (node*)-1, $3);
- }
- ;
-
-block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, 0, $6);
- }
- | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, $7, $8);
- }
- | f_arg ',' f_block_optarg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, 0, $4);
- }
- | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, $5, $6);
- }
- | f_arg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, 0, $4);
- }
- | f_arg ','
- {
- $$ = new_args(p, $1, 0, 1, 0, 0);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, $5, $6);
- }
- | f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, 0, 0, $2);
- }
- | f_block_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, 0, $4);
- }
- | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, $5, $6);
- }
- | f_block_optarg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, 0, $2);
- }
- | f_block_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, $3, $4);
- }
- | f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, 0, $2);
- }
- | f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, $3, $4);
- }
- | f_block_arg
- {
- $$ = new_args(p, 0, 0, 0, 0, $1);
- }
- ;
-
-opt_block_param : none
- | block_param_def
- {
- p->cmd_start = TRUE;
- $$ = $1;
- }
- ;
-
-block_param_def : '|' opt_bv_decl '|'
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- | tOROP
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- | '|' block_param opt_bv_decl '|'
- {
- $$ = $2;
- }
- ;
-
-
-opt_bv_decl : opt_nl
- {
- $$ = 0;
- }
- | opt_nl ';' bv_decls opt_nl
- {
- $$ = 0;
- }
- ;
-
-bv_decls : bvar
- | bv_decls ',' bvar
- ;
-
-bvar : tIDENTIFIER
- {
- local_add_f(p, $1);
- new_bv(p, $1);
- }
- | f_bad_arg
- ;
-
-f_larglist : '(' f_args opt_bv_decl ')'
- {
- $$ = $2;
- }
- | f_args
- {
- $$ = $1;
- }
- ;
-
-lambda_body : tLAMBEG compstmt '}'
- {
- $$ = $2;
- }
- | keyword_do_LAMBDA compstmt keyword_end
- {
- $$ = $2;
- }
- ;
-
-do_block : keyword_do_block
- {
- local_nest(p);
- }
- opt_block_param
- compstmt
- keyword_end
- {
- $$ = new_block(p,$3,$4);
- local_unnest(p);
- }
- ;
-
-block_call : command do_block
- {
- if ($1->car == (node*)NODE_YIELD) {
- yyerror(p, "block given to yield");
- }
- else {
- call_with_block(p, $1, $2);
- }
- $$ = $1;
- }
- | block_call dot_or_colon operation2 opt_paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | block_call dot_or_colon operation2 opt_paren_args brace_block
- {
- $$ = new_call(p, $1, $3, $4);
- call_with_block(p, $$, $5);
- }
- | block_call dot_or_colon operation2 command_args do_block
- {
- $$ = new_call(p, $1, $3, $4);
- call_with_block(p, $$, $5);
- }
- ;
-
-method_call : operation paren_args
- {
- $$ = new_fcall(p, $1, $2);
- }
- | primary_value '.' operation2 opt_paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation2 paren_args
- {
- $$ = new_call(p, $1, $3, $4);
- }
- | primary_value tCOLON2 operation3
- {
- $$ = new_call(p, $1, $3, 0);
- }
- | primary_value '.' paren_args
- {
- $$ = new_call(p, $1, intern("call",4), $3);
- }
- | primary_value tCOLON2 paren_args
- {
- $$ = new_call(p, $1, intern("call",4), $3);
- }
- | keyword_super paren_args
- {
- $$ = new_super(p, $2);
- }
- | keyword_super
- {
- $$ = new_zsuper(p);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = new_call(p, $1, intern("[]",2), $3);
- }
- ;
-
-brace_block : '{'
- {
- local_nest(p);
- $<num>$ = p->lineno;
- }
- opt_block_param
- compstmt '}'
- {
- $$ = new_block(p,$3,$4);
- SET_LINENO($$, $<num>2);
- local_unnest(p);
- }
- | keyword_do
- {
- local_nest(p);
- $<num>$ = p->lineno;
- }
- opt_block_param
- compstmt keyword_end
- {
- $$ = new_block(p,$3,$4);
- SET_LINENO($$, $<num>2);
- local_unnest(p);
- }
- ;
-
-case_body : keyword_when args then
- compstmt
- cases
- {
- $$ = cons(cons($2, $4), $5);
- }
- ;
-
-cases : opt_else
- {
- if ($1) {
- $$ = cons(cons(0, $1), 0);
- }
- else {
- $$ = 0;
- }
- }
- | case_body
- ;
-
-opt_rescue : keyword_rescue exc_list exc_var then
- compstmt
- opt_rescue
- {
- $$ = list1(list3($2, $3, $5));
- if ($6) $$ = append($$, $6);
- }
- | none
- ;
-
-exc_list : arg_value
- {
- $$ = list1($1);
- }
- | mrhs
- | none
- ;
-
-exc_var : tASSOC lhs
- {
- $$ = $2;
- }
- | none
- ;
-
-opt_ensure : keyword_ensure compstmt
- {
- $$ = $2;
- }
- | none
- ;
-
-literal : numeric
- | symbol
- | words
- | symbols
- ;
-
-string : tCHAR
- | tSTRING
- | tSTRING_BEG tSTRING
- {
- $$ = $2;
- }
- | tSTRING_BEG string_rep tSTRING
- {
- $$ = new_dstr(p, push($2, $3));
- }
- ;
-
-string_rep : string_interp
- | string_rep string_interp
- {
- $$ = append($1, $2);
- }
- ;
-
-string_interp : tSTRING_MID
- {
- $$ = list1($1);
- }
- | tSTRING_PART
- {
- $<nd>$ = p->lex_strterm;
- p->lex_strterm = NULL;
- }
- compstmt
- '}'
- {
- p->lex_strterm = $<nd>2;
- $$ = list2($1, $3);
- }
- | tLITERAL_DELIM
- {
- $$ = list1(new_literal_delim(p));
- }
- | tHD_LITERAL_DELIM heredoc_bodies
- {
- $$ = list1(new_literal_delim(p));
- }
- ;
-
-xstring : tXSTRING_BEG tXSTRING
- {
- $$ = $2;
- }
- | tXSTRING_BEG string_rep tXSTRING
- {
- $$ = new_dxstr(p, push($2, $3));
- }
- ;
-
-regexp : tREGEXP_BEG tREGEXP
- {
- $$ = $2;
- }
- | tREGEXP_BEG string_rep tREGEXP
- {
- $$ = new_dregx(p, $2, $3);
- }
- ;
-
-heredoc : tHEREDOC_BEG
- ;
-
-opt_heredoc_bodies : /* none */
- | heredoc_bodies
- ;
-
-heredoc_bodies : heredoc_body
- | heredoc_bodies heredoc_body
- ;
-
-heredoc_body : tHEREDOC_END
- {
- parser_heredoc_info * inf = parsing_heredoc_inf(p);
- inf->doc = push(inf->doc, new_str(p, "", 0));
- heredoc_end(p);
- }
- | heredoc_string_rep tHEREDOC_END
- {
- heredoc_end(p);
- }
- ;
-
-heredoc_string_rep : heredoc_string_interp
- | heredoc_string_rep heredoc_string_interp
- ;
-
-heredoc_string_interp : tHD_STRING_MID
- {
- parser_heredoc_info * inf = parsing_heredoc_inf(p);
- inf->doc = push(inf->doc, $1);
- heredoc_treat_nextline(p);
- }
- | tHD_STRING_PART
- {
- $<nd>$ = p->lex_strterm;
- p->lex_strterm = NULL;
- }
- compstmt
- '}'
- {
- parser_heredoc_info * inf = parsing_heredoc_inf(p);
- p->lex_strterm = $<nd>2;
- inf->doc = push(push(inf->doc, $1), $3);
- }
- ;
-
-words : tWORDS_BEG tSTRING
- {
- $$ = new_words(p, list1($2));
- }
- | tWORDS_BEG string_rep tSTRING
- {
- $$ = new_words(p, push($2, $3));
- }
- ;
-
-
-symbol : basic_symbol
- {
- $$ = new_sym(p, $1);
- }
- | tSYMBEG tSTRING_BEG string_interp tSTRING
- {
- p->lstate = EXPR_END;
- $$ = new_dsym(p, push($3, $4));
- }
- ;
-
-basic_symbol : tSYMBEG sym
- {
- p->lstate = EXPR_END;
- $$ = $2;
- }
- ;
-
-sym : fname
- | tIVAR
- | tGVAR
- | tCVAR
- | tSTRING
- {
- $$ = new_strsym(p, $1);
- }
- | tSTRING_BEG tSTRING
- {
- $$ = new_strsym(p, $2);
- }
- ;
-
-symbols : tSYMBOLS_BEG tSTRING
- {
- $$ = new_symbols(p, list1($2));
- }
- | tSYMBOLS_BEG string_rep tSTRING
- {
- $$ = new_symbols(p, push($2, $3));
- }
- ;
-
-numeric : tINTEGER
- | tFLOAT
- | tUMINUS_NUM tINTEGER %prec tLOWEST
- {
- $$ = negate_lit(p, $2);
- }
- | tUMINUS_NUM tFLOAT %prec tLOWEST
- {
- $$ = negate_lit(p, $2);
- }
- ;
-
-variable : tIDENTIFIER
- {
- $$ = new_lvar(p, $1);
- }
- | tIVAR
- {
- $$ = new_ivar(p, $1);
- }
- | tGVAR
- {
- $$ = new_gvar(p, $1);
- }
- | tCVAR
- {
- $$ = new_cvar(p, $1);
- }
- | tCONSTANT
- {
- $$ = new_const(p, $1);
- }
- ;
-
-var_lhs : variable
- {
- assignable(p, $1);
- }
- ;
-
-var_ref : variable
- {
- $$ = var_reference(p, $1);
- }
- | keyword_nil
- {
- $$ = new_nil(p);
- }
- | keyword_self
- {
- $$ = new_self(p);
- }
- | keyword_true
- {
- $$ = new_true(p);
- }
- | keyword_false
- {
- $$ = new_false(p);
- }
- | keyword__FILE__
- {
- if (!p->filename) {
- p->filename = "(null)";
- }
- $$ = new_str(p, p->filename, strlen(p->filename));
- }
- | keyword__LINE__
- {
- char buf[16];
-
- snprintf(buf, sizeof(buf), "%d", p->lineno);
- $$ = new_int(p, buf, 10);
- }
- ;
-
-backref : tNTH_REF
- | tBACK_REF
- ;
-
-superclass : term
- {
- $$ = 0;
- }
- | '<'
- {
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- }
- expr_value term
- {
- $$ = $3;
- }
- | error term
- {
- yyerrok;
- $$ = 0;
- }
- ;
-
-f_arglist : '(' f_args rparen
- {
- $$ = $2;
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- }
- | f_args term
- {
- $$ = $1;
- }
- ;
-
-f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, 0, $6);
- }
- | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, $5, $7, $8);
- }
- | f_arg ',' f_optarg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, 0, $4);
- }
- | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, $3, 0, $5, $6);
- }
- | f_arg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, 0, $4);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, $3, $5, $6);
- }
- | f_arg opt_f_block_arg
- {
- $$ = new_args(p, $1, 0, 0, 0, $2);
- }
- | f_optarg ',' f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, 0, $4);
- }
- | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, $3, $5, $6);
- }
- | f_optarg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, 0, $2);
- }
- | f_optarg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, $1, 0, $3, $4);
- }
- | f_rest_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, 0, $2);
- }
- | f_rest_arg ',' f_arg opt_f_block_arg
- {
- $$ = new_args(p, 0, 0, $1, $3, $4);
- }
- | f_block_arg
- {
- $$ = new_args(p, 0, 0, 0, 0, $1);
- }
- | /* none */
- {
- local_add_f(p, 0);
- $$ = new_args(p, 0, 0, 0, 0, 0);
- }
- ;
-
-f_bad_arg : tCONSTANT
- {
- yyerror(p, "formal argument cannot be a constant");
- $$ = 0;
- }
- | tIVAR
- {
- yyerror(p, "formal argument cannot be an instance variable");
- $$ = 0;
- }
- | tGVAR
- {
- yyerror(p, "formal argument cannot be a global variable");
- $$ = 0;
- }
- | tCVAR
- {
- yyerror(p, "formal argument cannot be a class variable");
- $$ = 0;
- }
- ;
-
-f_norm_arg : f_bad_arg
- {
- $$ = 0;
- }
- | tIDENTIFIER
- {
- local_add_f(p, $1);
- $$ = $1;
- }
- ;
-
-f_arg_item : f_norm_arg
- {
- $$ = new_arg(p, $1);
- }
- | tLPAREN f_margs rparen
- {
- $$ = new_masgn(p, $2, 0);
- }
- ;
-
-f_arg : f_arg_item
- {
- $$ = list1($1);
- }
- | f_arg ',' f_arg_item
- {
- $$ = push($1, $3);
- }
- ;
-
-f_opt_asgn : tIDENTIFIER '='
- {
- local_add_f(p, $1);
- $$ = $1;
- }
- ;
-
-f_opt : f_opt_asgn arg_value
- {
- $$ = cons(nsym($1), $2);
- }
- ;
-
-f_block_opt : f_opt_asgn primary_value
- {
- $$ = cons(nsym($1), $2);
- }
- ;
-
-f_block_optarg : f_block_opt
- {
- $$ = list1($1);
- }
- | f_block_optarg ',' f_block_opt
- {
- $$ = push($1, $3);
- }
- ;
-
-f_optarg : f_opt
- {
- $$ = list1($1);
- }
- | f_optarg ',' f_opt
- {
- $$ = push($1, $3);
- }
- ;
-
-restarg_mark : '*'
- | tSTAR
- ;
-
-f_rest_arg : restarg_mark tIDENTIFIER
- {
- local_add_f(p, $2);
- $$ = $2;
- }
- | restarg_mark
- {
- local_add_f(p, 0);
- $$ = -1;
- }
- ;
-
-blkarg_mark : '&'
- | tAMPER
- ;
-
-f_block_arg : blkarg_mark tIDENTIFIER
- {
- local_add_f(p, $2);
- $$ = $2;
- }
- ;
-
-opt_f_block_arg : ',' f_block_arg
- {
- $$ = $2;
- }
- | none
- {
- local_add_f(p, 0);
- $$ = 0;
- }
- ;
-
-singleton : var_ref
- {
- $$ = $1;
- if (!$$) $$ = new_nil(p);
- }
- | '(' {p->lstate = EXPR_BEG;} expr rparen
- {
- if ($3 == 0) {
- yyerror(p, "can't define singleton method for ().");
- }
- else {
- switch ((enum node_type)(int)(intptr_t)$3->car) {
- case NODE_STR:
- case NODE_DSTR:
- case NODE_XSTR:
- case NODE_DXSTR:
- case NODE_DREGX:
- case NODE_MATCH:
- case NODE_FLOAT:
- case NODE_ARRAY:
- case NODE_HEREDOC:
- yyerror(p, "can't define singleton method for literals");
- default:
- break;
- }
- }
- $$ = $3;
- }
- ;
-
-assoc_list : none
- | assocs trailer
- {
- $$ = $1;
- }
- ;
-
-assocs : assoc
- {
- $$ = list1($1);
- }
- | assocs ',' assoc
- {
- $$ = push($1, $3);
- }
- ;
-
-assoc : arg_value tASSOC arg_value
- {
- $$ = cons($1, $3);
- }
- | tLABEL arg_value
- {
- $$ = cons(new_sym(p, $1), $2);
- }
- ;
-
-operation : tIDENTIFIER
- | tCONSTANT
- | tFID
- ;
-
-operation2 : tIDENTIFIER
- | tCONSTANT
- | tFID
- | op
- ;
-
-operation3 : tIDENTIFIER
- | tFID
- | op
- ;
-
-dot_or_colon : '.'
- | tCOLON2
- ;
-
-opt_terms : /* none */
- | terms
- ;
-
-opt_nl : /* none */
- | nl
- ;
-
-rparen : opt_nl ')'
- ;
-
-rbracket : opt_nl ']'
- ;
-
-trailer : /* none */
- | nl
- | ','
- ;
-
-term : ';' {yyerrok;}
- | nl
- ;
-
-nl : '\n'
- {
- p->lineno++;
- p->column = 0;
- }
- opt_heredoc_bodies
-
-terms : term
- | terms ';' {yyerrok;}
- ;
-
-none : /* none */
- {
- $$ = 0;
- }
- ;
-%%
-#define yylval (*((YYSTYPE*)(p->ylval)))
-
-static void
-yyerror(parser_state *p, const char *s)
-{
- char* c;
- int n;
-
- if (! p->capture_errors) {
-#ifdef ENABLE_STDIO
- if (p->filename) {
- fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
- }
- else {
- fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
- }
-#endif
- }
- else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) {
- n = strlen(s);
- c = (char *)parser_palloc(p, n + 1);
- memcpy(c, s, n + 1);
- p->error_buffer[p->nerr].message = c;
- p->error_buffer[p->nerr].lineno = p->lineno;
- p->error_buffer[p->nerr].column = p->column;
- }
- p->nerr++;
-}
-
-static void
-yyerror_i(parser_state *p, const char *fmt, int i)
-{
- char buf[256];
-
- snprintf(buf, sizeof(buf), fmt, i);
- yyerror(p, buf);
-}
-
-static void
-yywarn(parser_state *p, const char *s)
-{
- char* c;
- int n;
-
- if (! p->capture_errors) {
-#ifdef ENABLE_STDIO
- if (p->filename) {
- fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
- }
- else {
- fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
- }
-#endif
- }
- else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) {
- n = strlen(s);
- c = (char *)parser_palloc(p, n + 1);
- memcpy(c, s, n + 1);
- p->warn_buffer[p->nwarn].message = c;
- p->warn_buffer[p->nwarn].lineno = p->lineno;
- p->warn_buffer[p->nwarn].column = p->column;
- }
- p->nwarn++;
-}
-
-static void
-yywarning(parser_state *p, const char *s)
-{
- yywarn(p, s);
-}
-
-static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
-{
- char buf[256];
-
- snprintf(buf, sizeof(buf), fmt, s);
- yywarning(p, buf);
-}
-
-static void
-backref_error(parser_state *p, node *n)
-{
- int c;
-
- c = (int)(intptr_t)n->car;
-
- if (c == NODE_NTH_REF) {
- yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr);
- }
- else if (c == NODE_BACK_REF) {
- yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
- }
- else {
- mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
- }
-}
-
-static void pushback(parser_state *p, int c);
-static mrb_bool peeks(parser_state *p, const char *s);
-static mrb_bool skips(parser_state *p, const char *s);
-
-static inline int
-nextc(parser_state *p)
-{
- int c;
-
- if (p->pb) {
- node *tmp;
-
- c = (int)(intptr_t)p->pb->car;
- tmp = p->pb;
- p->pb = p->pb->cdr;
- cons_free(tmp);
- }
- else {
-#ifdef ENABLE_STDIO
- if (p->f) {
- if (feof(p->f)) goto eof;
- c = fgetc(p->f);
- if (c == EOF) goto eof;
- }
- else
-#endif
- if (!p->s || p->s >= p->send) {
- goto eof;
- }
- else {
- c = (unsigned char)*p->s++;
- }
- }
- if (c >= 0) {
- p->column++;
- }
- if (c == '\r') {
- c = nextc(p);
- if (c != '\n') {
- pushback(p, c);
- return '\r';
- }
- return c;
- }
- return c;
-
- eof:
- if (!p->cxt) return -1;
- else {
- if (p->cxt->partial_hook(p) < 0)
- return -1; /* end of program(s) */
- return -2; /* end of a file in the program files */
- }
-}
-
-static void
-pushback(parser_state *p, int c)
-{
- if (c >= 0) {
- p->column--;
- }
- p->pb = cons((node*)(intptr_t)c, p->pb);
-}
-
-static void
-skip(parser_state *p, char term)
-{
- int c;
-
- for (;;) {
- c = nextc(p);
- if (c < 0) break;
- if (c == term) break;
- }
-}
-
-static int
-peekc_n(parser_state *p, int n)
-{
- node *list = 0;
- int c0;
-
- do {
- c0 = nextc(p);
- if (c0 == -1) return c0; /* do not skip partial EOF */
- list = push(list, (node*)(intptr_t)c0);
- } while(n--);
- if (p->pb) {
- p->pb = append((node*)list, p->pb);
- }
- else {
- p->pb = list;
- }
- return c0;
-}
-
-static mrb_bool
-peek_n(parser_state *p, int c, int n)
-{
- return peekc_n(p, n) == c && c >= 0;
-}
-#define peek(p,c) peek_n((p), (c), 0)
-
-static mrb_bool
-peeks(parser_state *p, const char *s)
-{
- int len = strlen(s);
-
-#ifdef ENABLE_STDIO
- if (p->f) {
- int n = 0;
- while (*s) {
- if (!peek_n(p, *s++, n++)) return FALSE;
- }
- return TRUE;
- }
- else
-#endif
- if (p->s && p->s + len <= p->send) {
- if (memcmp(p->s, s, len) == 0) return TRUE;
- }
- return FALSE;
-}
-
-static mrb_bool
-skips(parser_state *p, const char *s)
-{
- int c;
-
- for (;;) {
- /* skip until first char */
- for (;;) {
- c = nextc(p);
- if (c < 0) return c;
- if (c == '\n') {
- p->lineno++;
- p->column = 0;
- }
- if (c == *s) break;
- }
- s++;
- if (peeks(p, s)) {
- int len = strlen(s);
-
- while (len--) {
- if (nextc(p) == '\n') {
- p->lineno++;
- p->column = 0;
- }
- }
- return TRUE;
- }
- else{
- s--;
- }
- }
- return FALSE;
-}
-
-
-static int
-newtok(parser_state *p)
-{
- p->bidx = 0;
- return p->column - 1;
-}
-
-static void
-tokadd(parser_state *p, int32_t c)
-{
- char utf8[4];
- unsigned len;
-
- /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */
- if (c >= 0) {
- /* Single byte from source or non-Unicode escape */
- utf8[0] = (char)c;
- len = 1;
- }
- else {
- /* Unicode character */
- c = -c;
- if (c < 0x80) {
- utf8[0] = (char)c;
- len = 1;
- }
- else if (c < 0x800) {
- utf8[0] = (char)(0xC0 | (c >> 6));
- utf8[1] = (char)(0x80 | (c & 0x3F));
- len = 2;
- }
- else if (c < 0x10000) {
- utf8[0] = (char)(0xE0 | (c >> 12) );
- utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F));
- utf8[2] = (char)(0x80 | ( c & 0x3F));
- len = 3;
- }
- else {
- utf8[0] = (char)(0xF0 | (c >> 18) );
- utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F));
- utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F));
- utf8[3] = (char)(0x80 | ( c & 0x3F));
- len = 4;
- }
- }
- if (p->bidx+len <= MRB_PARSER_BUF_SIZE) {
- unsigned i;
- for (i = 0; i < len; i++) {
- p->buf[p->bidx++] = utf8[i];
- }
- }
-}
-
-static int
-toklast(parser_state *p)
-{
- return p->buf[p->bidx-1];
-}
-
-static void
-tokfix(parser_state *p)
-{
- if (p->bidx >= MRB_PARSER_BUF_SIZE) {
- yyerror(p, "string too long (truncated)");
- }
- p->buf[p->bidx] = '\0';
-}
-
-static const char*
-tok(parser_state *p)
-{
- return p->buf;
-}
-
-static int
-toklen(parser_state *p)
-{
- return p->bidx;
-}
-
-#define IS_ARG() (p->lstate == EXPR_ARG || p->lstate == EXPR_CMDARG)
-#define IS_END() (p->lstate == EXPR_END || p->lstate == EXPR_ENDARG || p->lstate == EXPR_ENDFN)
-#define IS_BEG() (p->lstate == EXPR_BEG || p->lstate == EXPR_MID || p->lstate == EXPR_VALUE || p->lstate == EXPR_CLASS)
-#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c))
-#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG())
-#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
-
-static int
-scan_oct(const int *start, int len, int *retlen)
-{
- const int *s = start;
- int retval = 0;
-
- /* mrb_assert(len <= 3) */
- while (len-- && *s >= '0' && *s <= '7') {
- retval <<= 3;
- retval |= *s++ - '0';
- }
- *retlen = s - start;
-
- return retval;
-}
-
-static int32_t
-scan_hex(const int *start, int len, int *retlen)
-{
- static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
- const int *s = start;
- int32_t retval = 0;
- char *tmp;
-
- /* mrb_assert(len <= 8) */
- while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) {
- retval <<= 4;
- retval |= (tmp - hexdigit) & 15;
- s++;
- }
- *retlen = s - start;
-
- return retval;
-}
-
-/* Return negative to indicate Unicode code point */
-static int32_t
-read_escape(parser_state *p)
-{
- int32_t c;
-
- switch (c = nextc(p)) {
- case '\\':/* Backslash */
- return c;
-
- case 'n':/* newline */
- return '\n';
-
- case 't':/* horizontal tab */
- return '\t';
-
- case 'r':/* carriage-return */
- return '\r';
-
- case 'f':/* form-feed */
- return '\f';
-
- case 'v':/* vertical tab */
- return '\13';
-
- case 'a':/* alarm(bell) */
- return '\007';
-
- case 'e':/* escape */
- return 033;
-
- case '0': case '1': case '2': case '3': /* octal constant */
- case '4': case '5': case '6': case '7':
- {
- int buf[3];
- int i;
-
- buf[0] = c;
- for (i=1; i<3; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (buf[i] < '0' || '7' < buf[i]) {
- pushback(p, buf[i]);
- break;
- }
- }
- c = scan_oct(buf, i, &i);
- }
- return c;
-
- case 'x': /* hex constant */
- {
- int buf[2];
- int i;
-
- for (i=0; i<2; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (!ISXDIGIT(buf[i])) {
- pushback(p, buf[i]);
- break;
- }
- }
- c = scan_hex(buf, i, &i);
- if (i == 0) {
- yyerror(p, "Invalid escape character syntax");
- return 0;
- }
- }
- return c;
-
- case 'u': /* Unicode */
- {
- int buf[9];
- int i;
-
- /* Look for opening brace */
- i = 0;
- buf[0] = nextc(p);
- if (buf[0] < 0) goto eof;
- if (buf[0] == '{') {
- /* \u{xxxxxxxx} form */
- for (i=0; i<9; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (buf[i] == '}') {
- break;
- }
- else if (!ISXDIGIT(buf[i])) {
- yyerror(p, "Invalid escape character syntax");
- pushback(p, buf[i]);
- return 0;
- }
- }
- }
- else if (ISXDIGIT(buf[0])) {
- /* \uxxxx form */
- for (i=1; i<4; i++) {
- buf[i] = nextc(p);
- if (buf[i] < 0) goto eof;
- if (!ISXDIGIT(buf[i])) {
- pushback(p, buf[i]);
- break;
- }
- }
- }
- else {
- pushback(p, buf[0]);
- }
- c = scan_hex(buf, i, &i);
- if (i == 0) {
- yyerror(p, "Invalid escape character syntax");
- return 0;
- }
- if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
- yyerror(p, "Invalid Unicode code point");
- return 0;
- }
- }
- return -c;
-
- case 'b':/* backspace */
- return '\010';
-
- case 's':/* space */
- return ' ';
-
- case 'M':
- if ((c = nextc(p)) != '-') {
- yyerror(p, "Invalid escape character syntax");
- pushback(p, c);
- return '\0';
- }
- if ((c = nextc(p)) == '\\') {
- return read_escape(p) | 0x80;
- }
- else if (c < 0) goto eof;
- else {
- return ((c & 0xff) | 0x80);
- }
-
- case 'C':
- if ((c = nextc(p)) != '-') {
- yyerror(p, "Invalid escape character syntax");
- pushback(p, c);
- return '\0';
- }
- case 'c':
- if ((c = nextc(p))== '\\') {
- c = read_escape(p);
- }
- else if (c == '?')
- return 0177;
- else if (c < 0) goto eof;
- return c & 0x9f;
-
- eof:
- case -1:
- case -2: /* end of a file */
- yyerror(p, "Invalid escape character syntax");
- return '\0';
-
- default:
- return c;
- }
-}
-
-static int
-parse_string(parser_state *p)
-{
- int c;
- string_type type = (string_type)(intptr_t)p->lex_strterm->car;
- int nest_level = (intptr_t)p->lex_strterm->cdr->car;
- int beg = (intptr_t)p->lex_strterm->cdr->cdr->car;
- int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr;
- parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
-
- newtok(p);
- while ((c = nextc(p)) != end || nest_level != 0) {
- if (hinf && (c == '\n' || c < 0)) {
- int line_head;
- tokadd(p, '\n');
- tokfix(p);
- p->lineno++;
- p->column = 0;
- line_head = hinf->line_head;
- hinf->line_head = TRUE;
- if (line_head) {
- /* check whether end of heredoc */
- const char *s = tok(p);
- int len = toklen(p);
- if (hinf->allow_indent) {
- while (ISSPACE(*s) && len > 0) {
- ++s;
- --len;
- }
- }
- if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
- return tHEREDOC_END;
- }
- }
- if (c < 0) {
- char buf[256];
- snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
- yyerror(p, buf);
- return 0;
- }
- yylval.nd = new_str(p, tok(p), toklen(p));
- return tHD_STRING_MID;
- }
- if (c < 0) {
- yyerror(p, "unterminated string meets end of file");
- return 0;
- }
- else if (c == beg) {
- nest_level++;
- p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
- }
- else if (c == end) {
- nest_level--;
- p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
- }
- else if (c == '\\') {
- c = nextc(p);
- if (type & STR_FUNC_EXPAND) {
- if (c == end || c == beg) {
- tokadd(p, c);
- }
- else if (c == '\n') {
- p->lineno++;
- p->column = 0;
- if (type & STR_FUNC_ARRAY) {
- tokadd(p, '\n');
- }
- }
- else if (type & STR_FUNC_REGEXP) {
- tokadd(p, '\\');
- tokadd(p, c);
- }
- else {
- pushback(p, c);
- tokadd(p, read_escape(p));
- if (hinf)
- hinf->line_head = FALSE;
- }
- }
- else {
- if (c != beg && c != end) {
- if (c == '\n') {
- p->lineno++;
- p->column = 0;
- }
- if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) {
- tokadd(p, '\\');
- }
- }
- tokadd(p, c);
- }
- continue;
- }
- else if ((c == '#') && (type & STR_FUNC_EXPAND)) {
- c = nextc(p);
- if (c == '{') {
- tokfix(p);
- p->lstate = EXPR_BEG;
- p->cmd_start = TRUE;
- yylval.nd = new_str(p, tok(p), toklen(p));
- if (hinf) {
- hinf->line_head = FALSE;
- return tHD_STRING_PART;
- }
- return tSTRING_PART;
- }
- tokadd(p, '#');
- pushback(p, c);
- continue;
- }
- if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) {
- if (toklen(p) == 0) {
- do {
- if (c == '\n') {
- p->lineno++;
- p->column = 0;
- heredoc_treat_nextline(p);
- if (p->parsing_heredoc != NULL) {
- return tHD_LITERAL_DELIM;
- }
- }
- c = nextc(p);
- } while (ISSPACE(c));
- pushback(p, c);
- return tLITERAL_DELIM;
- }
- else {
- pushback(p, c);
- tokfix(p);
- yylval.nd = new_str(p, tok(p), toklen(p));
- return tSTRING_MID;
- }
- }
- tokadd(p, c);
- }
-
- tokfix(p);
- p->lstate = EXPR_END;
- end_strterm(p);
-
- if (type & STR_FUNC_XQUOTE) {
- yylval.nd = new_xstr(p, tok(p), toklen(p));
- return tXSTRING;
- }
-
- if (type & STR_FUNC_REGEXP) {
- int f = 0;
- int c;
- char *s = strndup(tok(p), toklen(p));
- char flags[3];
- char *flag = flags;
- char *dup;
-
- newtok(p);
- while (c = nextc(p), c >= 0 && ISALPHA(c)) {
- switch (c) {
- case 'i': f |= 1; break;
- case 'x': f |= 2; break;
- case 'm': f |= 4; break;
- default: tokadd(p, c); break;
- }
- }
- pushback(p, c);
- if (toklen(p)) {
- char msg[128];
- tokfix(p);
- snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
- toklen(p) > 1 ? "s" : "", tok(p));
- yyerror(p, msg);
- }
- if (f != 0) {
- if (f & 1) *flag++ = 'i';
- if (f & 2) *flag++ = 'x';
- if (f & 4) *flag++ = 'm';
- dup = strndup(flags, (size_t)(flag - flags));
- }
- else {
- dup = NULL;
- }
- yylval.nd = new_regx(p, s, dup);
-
- return tREGEXP;
- }
-
- yylval.nd = new_str(p, tok(p), toklen(p));
- return tSTRING;
-}
-
-
-static int
-heredoc_identifier(parser_state *p)
-{
- int c;
- int type = str_heredoc;
- mrb_bool indent = FALSE;
- mrb_bool quote = FALSE;
- node *newnode;
- parser_heredoc_info *info;
-
- c = nextc(p);
- if (ISSPACE(c) || c == '=') {
- pushback(p, c);
- return 0;
- }
- if (c == '-') {
- indent = TRUE;
- c = nextc(p);
- }
- if (c == '\'' || c == '"') {
- int term = c;
- if (c == '\'')
- quote = TRUE;
- newtok(p);
- while ((c = nextc(p)) >= 0 && c != term) {
- if (c == '\n') {
- c = -1;
- break;
- }
- tokadd(p, c);
- }
- if (c < 0) {
- yyerror(p, "unterminated here document identifier");
- return 0;
- }
- }
- else {
- if (c < 0) {
- return 0; /* missing here document identifier */
- }
- if (! identchar(c)) {
- pushback(p, c);
- if (indent) pushback(p, '-');
- return 0;
- }
- newtok(p);
- do {
- tokadd(p, c);
- } while ((c = nextc(p)) >= 0 && identchar(c));
- pushback(p, c);
- }
- tokfix(p);
- newnode = new_heredoc(p);
- info = (parser_heredoc_info*)newnode->cdr;
- info->term = strndup(tok(p), toklen(p));
- info->term_len = toklen(p);
- if (! quote)
- type |= STR_FUNC_EXPAND;
- info->type = (string_type)type;
- info->allow_indent = indent;
- info->line_head = TRUE;
- info->doc = NULL;
- p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
- p->lstate = EXPR_END;
-
- yylval.nd = newnode;
- return tHEREDOC_BEG;
-}
-
-static int
-arg_ambiguous(parser_state *p)
-{
- yywarning(p, "ambiguous first argument; put parentheses or even spaces");
- return 1;
-}
-
-#include "lex.def"
-
-static int
-parser_yylex(parser_state *p)
-{
- int32_t c;
- int space_seen = 0;
- int cmd_state;
- enum mrb_lex_state_enum last_state;
- int token_column;
-
- if (p->lex_strterm) {
- if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
- if (p->parsing_heredoc != NULL)
- return parse_string(p);
- }
- else
- return parse_string(p);
- }
- cmd_state = p->cmd_start;
- p->cmd_start = FALSE;
- retry:
- last_state = p->lstate;
- switch (c = nextc(p)) {
- case '\0': /* NUL */
- case '\004': /* ^D */
- case '\032': /* ^Z */
- return 0;
- case -1: /* end of script. */
- if (p->heredocs_from_nextline)
- goto maybe_heredoc;
- return 0;
-
- /* white spaces */
- case ' ': case '\t': case '\f': case '\r':
- case '\13': /* '\v' */
- space_seen = 1;
- goto retry;
-
- case '#': /* it's a comment */
- skip(p, '\n');
- /* fall through */
- case -2: /* end of a file */
- case '\n':
- maybe_heredoc:
- heredoc_treat_nextline(p);
- switch (p->lstate) {
- case EXPR_BEG:
- case EXPR_FNAME:
- case EXPR_DOT:
- case EXPR_CLASS:
- case EXPR_VALUE:
- p->lineno++;
- p->column = 0;
- if (p->parsing_heredoc != NULL) {
- return parse_string(p);
- }
- goto retry;
- default:
- break;
- }
- if (p->parsing_heredoc != NULL) {
- return '\n';
- }
- while ((c = nextc(p))) {
- switch (c) {
- case ' ': case '\t': case '\f': case '\r':
- case '\13': /* '\v' */
- space_seen = 1;
- break;
- case '.':
- if ((c = nextc(p)) != '.') {
- pushback(p, c);
- pushback(p, '.');
- goto retry;
- }
- case -1: /* EOF */
- case -2: /* end of a file */
- goto normal_newline;
- default:
- pushback(p, c);
- goto normal_newline;
- }
- }
- normal_newline:
- p->cmd_start = TRUE;
- p->lstate = EXPR_BEG;
- return '\n';
-
- case '*':
- if ((c = nextc(p)) == '*') {
- if ((c = nextc(p)) == '=') {
- yylval.id = intern("**",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- c = tPOW;
- }
- else {
- if (c == '=') {
- yylval.id = intern_c('*');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- yywarning(p, "`*' interpreted as argument prefix");
- c = tSTAR;
- }
- else if (IS_BEG()) {
- c = tSTAR;
- }
- else {
- c = '*';
- }
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- return c;
-
- case '!':
- c = nextc(p);
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- if (c == '@') {
- return '!';
- }
- }
- else {
- p->lstate = EXPR_BEG;
- }
- if (c == '=') {
- return tNEQ;
- }
- if (c == '~') {
- return tNMATCH;
- }
- pushback(p, c);
- return '!';
-
- case '=':
- if (p->column == 1) {
- static const char begin[] = "begin";
- static const char end[] = "\n=end";
- if (peeks(p, begin)) {
- c = peekc_n(p, sizeof(begin)-1);
- if (c < 0 || ISSPACE(c)) {
- do {
- if (!skips(p, end)) {
- yyerror(p, "embedded document meets end of file");
- return 0;
- }
- c = nextc(p);
- } while (!(c < 0 || ISSPACE(c)));
- if (c != '\n') skip(p, '\n');
- p->lineno++;
- p->column = 0;
- goto retry;
- }
- }
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- if ((c = nextc(p)) == '=') {
- if ((c = nextc(p)) == '=') {
- return tEQQ;
- }
- pushback(p, c);
- return tEQ;
- }
- if (c == '~') {
- return tMATCH;
- }
- else if (c == '>') {
- return tASSOC;
- }
- pushback(p, c);
- return '=';
-
- case '<':
- c = nextc(p);
- if (c == '<' &&
- p->lstate != EXPR_DOT &&
- p->lstate != EXPR_CLASS &&
- !IS_END() &&
- (!IS_ARG() || space_seen)) {
- int token = heredoc_identifier(p);
- if (token)
- return token;
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- if (p->lstate == EXPR_CLASS) {
- p->cmd_start = TRUE;
- }
- }
- if (c == '=') {
- if ((c = nextc(p)) == '>') {
- return tCMP;
- }
- pushback(p, c);
- return tLEQ;
- }
- if (c == '<') {
- if ((c = nextc(p)) == '=') {
- yylval.id = intern("<<",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- return tLSHFT;
- }
- pushback(p, c);
- return '<';
-
- case '>':
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- if ((c = nextc(p)) == '=') {
- return tGEQ;
- }
- if (c == '>') {
- if ((c = nextc(p)) == '=') {
- yylval.id = intern(">>",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- return tRSHFT;
- }
- pushback(p, c);
- return '>';
-
- case '"':
- p->lex_strterm = new_strterm(p, str_dquote, '"', 0);
- return tSTRING_BEG;
-
- case '\'':
- p->lex_strterm = new_strterm(p, str_squote, '\'', 0);
- return parse_string(p);
-
- case '`':
- if (p->lstate == EXPR_FNAME) {
- p->lstate = EXPR_ENDFN;
- return '`';
- }
- if (p->lstate == EXPR_DOT) {
- if (cmd_state)
- p->lstate = EXPR_CMDARG;
- else
- p->lstate = EXPR_ARG;
- return '`';
- }
- p->lex_strterm = new_strterm(p, str_xquote, '`', 0);
- return tXSTRING_BEG;
-
- case '?':
- if (IS_END()) {
- p->lstate = EXPR_VALUE;
- return '?';
- }
- c = nextc(p);
- if (c < 0) {
- yyerror(p, "incomplete character syntax");
- return 0;
- }
- if (ISSPACE(c)) {
- if (!IS_ARG()) {
- int c2;
- switch (c) {
- case ' ':
- c2 = 's';
- break;
- case '\n':
- c2 = 'n';
- break;
- case '\t':
- c2 = 't';
- break;
- case '\v':
- c2 = 'v';
- break;
- case '\r':
- c2 = 'r';
- break;
- case '\f':
- c2 = 'f';
- break;
- default:
- c2 = 0;
- break;
- }
- if (c2) {
- char buf[256];
- snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
- yyerror(p, buf);
- }
- }
- ternary:
- pushback(p, c);
- p->lstate = EXPR_VALUE;
- return '?';
- }
- newtok(p);
- /* need support UTF-8 if configured */
- if ((isalnum(c) || c == '_')) {
- int c2 = nextc(p);
- pushback(p, c2);
- if ((isalnum(c2) || c2 == '_')) {
- goto ternary;
- }
- }
- if (c == '\\') {
- c = read_escape(p);
- tokadd(p, c);
- }
- else {
- tokadd(p, c);
- }
- tokfix(p);
- yylval.nd = new_str(p, tok(p), toklen(p));
- p->lstate = EXPR_END;
- return tCHAR;
-
- case '&':
- if ((c = nextc(p)) == '&') {
- p->lstate = EXPR_BEG;
- if ((c = nextc(p)) == '=') {
- yylval.id = intern("&&",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- return tANDOP;
- }
- else if (c == '=') {
- yylval.id = intern_c('&');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- yywarning(p, "`&' interpreted as argument prefix");
- c = tAMPER;
- }
- else if (IS_BEG()) {
- c = tAMPER;
- }
- else {
- c = '&';
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- return c;
-
- case '|':
- if ((c = nextc(p)) == '|') {
- p->lstate = EXPR_BEG;
- if ((c = nextc(p)) == '=') {
- yylval.id = intern("||",2);
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- return tOROP;
- }
- if (c == '=') {
- yylval.id = intern_c('|');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- pushback(p, c);
- return '|';
-
- case '+':
- c = nextc(p);
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- if (c == '@') {
- return tUPLUS;
- }
- pushback(p, c);
- return '+';
- }
- if (c == '=') {
- yylval.id = intern_c('+');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
- p->lstate = EXPR_BEG;
- pushback(p, c);
- if (c >= 0 && ISDIGIT(c)) {
- c = '+';
- goto start_num;
- }
- return tUPLUS;
- }
- p->lstate = EXPR_BEG;
- pushback(p, c);
- return '+';
-
- case '-':
- c = nextc(p);
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- if (c == '@') {
- return tUMINUS;
- }
- pushback(p, c);
- return '-';
- }
- if (c == '=') {
- yylval.id = intern_c('-');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- if (c == '>') {
- p->lstate = EXPR_ENDFN;
- return tLAMBDA;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
- p->lstate = EXPR_BEG;
- pushback(p, c);
- if (c >= 0 && ISDIGIT(c)) {
- return tUMINUS_NUM;
- }
- return tUMINUS;
- }
- p->lstate = EXPR_BEG;
- pushback(p, c);
- return '-';
-
- case '.':
- p->lstate = EXPR_BEG;
- if ((c = nextc(p)) == '.') {
- if ((c = nextc(p)) == '.') {
- return tDOT3;
- }
- pushback(p, c);
- return tDOT2;
- }
- pushback(p, c);
- if (c >= 0 && ISDIGIT(c)) {
- yyerror(p, "no .<digit> floating literal anymore; put 0 before dot");
- }
- p->lstate = EXPR_DOT;
- return '.';
-
- start_num:
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- int is_float, seen_point, seen_e, nondigit;
-
- is_float = seen_point = seen_e = nondigit = 0;
- p->lstate = EXPR_END;
- newtok(p);
- if (c == '-' || c == '+') {
- tokadd(p, c);
- c = nextc(p);
- }
- if (c == '0') {
-#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0)
- int start = toklen(p);
- c = nextc(p);
- if (c == 'x' || c == 'X') {
- /* hexadecimal */
- c = nextc(p);
- if (c >= 0 && ISXDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISXDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, tolower(c));
- } while ((c = nextc(p)) >= 0);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 16);
- return tINTEGER;
- }
- if (c == 'b' || c == 'B') {
- /* binary */
- c = nextc(p);
- if (c == '0' || c == '1') {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c != '0' && c != '1') break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) >= 0);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 2);
- return tINTEGER;
- }
- if (c == 'd' || c == 'D') {
- /* decimal */
- c = nextc(p);
- if (c >= 0 && ISDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) >= 0);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- no_digits();
- }
- else if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 10);
- return tINTEGER;
- }
- if (c == '_') {
- /* 0_0 */
- goto octal_number;
- }
- if (c == 'o' || c == 'O') {
- /* prefixed octal */
- c = nextc(p);
- if (c < 0 || c == '_' || !ISDIGIT(c)) {
- no_digits();
- }
- }
- if (c >= '0' && c <= '7') {
- /* octal */
- octal_number:
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c < '0' || c > '9') break;
- if (c > '7') goto invalid_octal;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) >= 0);
-
- if (toklen(p) > start) {
- pushback(p, c);
- tokfix(p);
- if (nondigit) goto trailing_uc;
- yylval.nd = new_int(p, tok(p), 8);
- return tINTEGER;
- }
- if (nondigit) {
- pushback(p, c);
- goto trailing_uc;
- }
- }
- if (c > '7' && c <= '9') {
- invalid_octal:
- yyerror(p, "Invalid octal digit");
- }
- else if (c == '.' || c == 'e' || c == 'E') {
- tokadd(p, '0');
- }
- else {
- pushback(p, c);
- yylval.nd = new_int(p, "0", 10);
- return tINTEGER;
- }
- }
-
- for (;;) {
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- nondigit = 0;
- tokadd(p, c);
- break;
-
- case '.':
- if (nondigit) goto trailing_uc;
- if (seen_point || seen_e) {
- goto decode_num;
- }
- else {
- int c0 = nextc(p);
- if (c0 < 0 || !ISDIGIT(c0)) {
- pushback(p, c0);
- goto decode_num;
- }
- c = c0;
- }
- tokadd(p, '.');
- tokadd(p, c);
- is_float++;
- seen_point++;
- nondigit = 0;
- break;
-
- case 'e':
- case 'E':
- if (nondigit) {
- pushback(p, c);
- c = nondigit;
- goto decode_num;
- }
- if (seen_e) {
- goto decode_num;
- }
- tokadd(p, c);
- seen_e++;
- is_float++;
- nondigit = c;
- c = nextc(p);
- if (c != '-' && c != '+') continue;
- tokadd(p, c);
- nondigit = c;
- break;
-
- case '_': /* `_' in number just ignored */
- if (nondigit) goto decode_num;
- nondigit = c;
- break;
-
- default:
- goto decode_num;
- }
- c = nextc(p);
- }
-
- decode_num:
- pushback(p, c);
- if (nondigit) {
- trailing_uc:
- yyerror_i(p, "trailing `%c' in number", nondigit);
- }
- tokfix(p);
- if (is_float) {
- double d;
- char *endp;
-
- errno = 0;
- d = strtod(tok(p), &endp);
- if (d == 0 && endp == tok(p)) {
- yywarning_s(p, "corrupted float value %s", tok(p));
- }
- else if (errno == ERANGE) {
- yywarning_s(p, "float %s out of range", tok(p));
- errno = 0;
- }
- yylval.nd = new_float(p, tok(p));
- return tFLOAT;
- }
- yylval.nd = new_int(p, tok(p), 10);
- return tINTEGER;
- }
-
- case ')':
- case ']':
- p->paren_nest--;
- case '}':
- COND_LEXPOP();
- CMDARG_LEXPOP();
- if (c == ')')
- p->lstate = EXPR_ENDFN;
- else
- p->lstate = EXPR_ENDARG;
- return c;
-
- case ':':
- c = nextc(p);
- if (c == ':') {
- if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) {
- p->lstate = EXPR_BEG;
- return tCOLON3;
- }
- p->lstate = EXPR_DOT;
- return tCOLON2;
- }
- if (IS_END() || ISSPACE(c)) {
- pushback(p, c);
- p->lstate = EXPR_BEG;
- return ':';
- }
- pushback(p, c);
- p->lstate = EXPR_FNAME;
- return tSYMBEG;
-
- case '/':
- if (IS_BEG()) {
- p->lex_strterm = new_strterm(p, str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- if ((c = nextc(p)) == '=') {
- yylval.id = intern_c('/');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- p->lex_strterm = new_strterm(p, str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- return '/';
-
- case '^':
- if ((c = nextc(p)) == '=') {
- yylval.id = intern_c('^');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- pushback(p, c);
- return '^';
-
- case ';':
- p->lstate = EXPR_BEG;
- return ';';
-
- case ',':
- p->lstate = EXPR_BEG;
- return ',';
-
- case '~':
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- if ((c = nextc(p)) != '@') {
- pushback(p, c);
- }
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- return '~';
-
- case '(':
- if (IS_BEG()) {
- c = tLPAREN;
- }
- else if (IS_SPCARG(-1)) {
- c = tLPAREN_ARG;
- }
- p->paren_nest++;
- COND_PUSH(0);
- CMDARG_PUSH(0);
- p->lstate = EXPR_BEG;
- return c;
-
- case '[':
- p->paren_nest++;
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- if ((c = nextc(p)) == ']') {
- if ((c = nextc(p)) == '=') {
- return tASET;
- }
- pushback(p, c);
- return tAREF;
- }
- pushback(p, c);
- return '[';
- }
- else if (IS_BEG()) {
- c = tLBRACK;
- }
- else if (IS_ARG() && space_seen) {
- c = tLBRACK;
- }
- p->lstate = EXPR_BEG;
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return c;
-
- case '{':
- if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
- p->lstate = EXPR_BEG;
- p->lpar_beg = 0;
- p->paren_nest--;
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return tLAMBEG;
- }
- if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN)
- c = '{'; /* block (primary) */
- else if (p->lstate == EXPR_ENDARG)
- c = tLBRACE_ARG; /* block (expr) */
- else
- c = tLBRACE; /* hash */
- COND_PUSH(0);
- CMDARG_PUSH(0);
- p->lstate = EXPR_BEG;
- return c;
-
- case '\\':
- c = nextc(p);
- if (c == '\n') {
- p->lineno++;
- p->column = 0;
- space_seen = 1;
- goto retry; /* skip \\n */
- }
- pushback(p, c);
- return '\\';
-
- case '%':
- if (IS_BEG()) {
- int term;
- int paren;
-
- c = nextc(p);
- quotation:
- if (c < 0 || !ISALNUM(c)) {
- term = c;
- c = 'Q';
- }
- else {
- term = nextc(p);
- if (isalnum(term)) {
- yyerror(p, "unknown type of %string");
- return 0;
- }
- }
- if (c < 0 || term < 0) {
- yyerror(p, "unterminated quoted string meets end of file");
- return 0;
- }
- paren = term;
- if (term == '(') term = ')';
- else if (term == '[') term = ']';
- else if (term == '{') term = '}';
- else if (term == '<') term = '>';
- else paren = 0;
-
- switch (c) {
- case 'Q':
- p->lex_strterm = new_strterm(p, str_dquote, term, paren);
- return tSTRING_BEG;
-
- case 'q':
- p->lex_strterm = new_strterm(p, str_squote, term, paren);
- return parse_string(p);
-
- case 'W':
- p->lex_strterm = new_strterm(p, str_dword, term, paren);
- return tWORDS_BEG;
-
- case 'w':
- p->lex_strterm = new_strterm(p, str_sword, term, paren);
- return tWORDS_BEG;
-
- case 'x':
- p->lex_strterm = new_strterm(p, str_xquote, term, paren);
- return tXSTRING_BEG;
-
- case 'r':
- p->lex_strterm = new_strterm(p, str_regexp, term, paren);
- return tREGEXP_BEG;
-
- case 's':
- p->lex_strterm = new_strterm(p, str_ssym, term, paren);
- return tSYMBEG;
-
- case 'I':
- p->lex_strterm = new_strterm(p, str_dsymbols, term, paren);
- return tSYMBOLS_BEG;
-
- case 'i':
- p->lex_strterm = new_strterm(p, str_ssymbols, term, paren);
- return tSYMBOLS_BEG;
-
- default:
- yyerror(p, "unknown type of %string");
- return 0;
- }
- }
- if ((c = nextc(p)) == '=') {
- yylval.id = intern_c('%');
- p->lstate = EXPR_BEG;
- return tOP_ASGN;
- }
- if (IS_SPCARG(c)) {
- goto quotation;
- }
- if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
- p->lstate = EXPR_ARG;
- }
- else {
- p->lstate = EXPR_BEG;
- }
- pushback(p, c);
- return '%';
-
- case '$':
- p->lstate = EXPR_END;
- token_column = newtok(p);
- c = nextc(p);
- if (c < 0) {
- yyerror(p, "incomplete global variable syntax");
- return 0;
- }
- switch (c) {
- case '_': /* $_: last read line string */
- c = nextc(p);
- if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */
- tokadd(p, '$');
- tokadd(p, c);
- break;
- }
- pushback(p, c);
- c = '_';
- /* fall through */
- case '~': /* $~: match-data */
- case '*': /* $*: argv */
- case '$': /* $$: pid */
- case '?': /* $?: last status */
- case '!': /* $!: error string */
- case '@': /* $@: error position */
- case '/': /* $/: input record separator */
- case '\\': /* $\: output record separator */
- case ';': /* $;: field separator */
- case ',': /* $,: output field separator */
- case '.': /* $.: last read line number */
- case '=': /* $=: ignorecase */
- case ':': /* $:: load path */
- case '<': /* $<: reading filename */
- case '>': /* $>: default output handle */
- case '\"': /* $": already loaded files */
- tokadd(p, '$');
- tokadd(p, c);
- tokfix(p);
- yylval.id = intern_cstr(tok(p));
- return tGVAR;
-
- case '-':
- tokadd(p, '$');
- tokadd(p, c);
- c = nextc(p);
- pushback(p, c);
- gvar:
- tokfix(p);
- yylval.id = intern_cstr(tok(p));
- return tGVAR;
-
- case '&': /* $&: last match */
- case '`': /* $`: string before last match */
- case '\'': /* $': string after last match */
- case '+': /* $+: string matches last pattern */
- if (last_state == EXPR_FNAME) {
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
- }
- yylval.nd = new_back_ref(p, c);
- return tBACK_REF;
-
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9':
- do {
- tokadd(p, c);
- c = nextc(p);
- } while (c >= 0 && isdigit(c));
- pushback(p, c);
- if (last_state == EXPR_FNAME) goto gvar;
- tokfix(p);
- yylval.nd = new_nth_ref(p, atoi(tok(p)));
- return tNTH_REF;
-
- default:
- if (!identchar(c)) {
- pushback(p, c);
- return '$';
- }
- case '0':
- tokadd(p, '$');
- }
- break;
-
- case '@':
- c = nextc(p);
- token_column = newtok(p);
- tokadd(p, '@');
- if (c == '@') {
- tokadd(p, '@');
- c = nextc(p);
- }
- if (c < 0) {
- if (p->bidx == 1) {
- yyerror(p, "incomplete instance variable syntax");
- }
- else {
- yyerror(p, "incomplete class variable syntax");
- }
- return 0;
- }
- else if (isdigit(c)) {
- if (p->bidx == 1) {
- yyerror_i(p, "`@%c' is not allowed as an instance variable name", c);
- }
- else {
- yyerror_i(p, "`@@%c' is not allowed as a class variable name", c);
- }
- return 0;
- }
- if (!identchar(c)) {
- pushback(p, c);
- return '@';
- }
- break;
-
- case '_':
- token_column = newtok(p);
- break;
-
- default:
- if (!identchar(c)) {
- yyerror_i(p, "Invalid char `\\x%02X' in expression", c);
- goto retry;
- }
-
- token_column = newtok(p);
- break;
- }
-
- do {
- tokadd(p, c);
- c = nextc(p);
- if (c < 0) break;
- } while (identchar(c));
- if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') &&
- strncmp(tok(p), "__END__", toklen(p)) == 0)
- return -1;
-
- switch (tok(p)[0]) {
- case '@': case '$':
- pushback(p, c);
- break;
- default:
- if ((c == '!' || c == '?') && !peek(p, '=')) {
- tokadd(p, c);
- }
- else {
- pushback(p, c);
- }
- }
- tokfix(p);
- {
- int result = 0;
-
- switch (tok(p)[0]) {
- case '$':
- p->lstate = EXPR_END;
- result = tGVAR;
- break;
- case '@':
- p->lstate = EXPR_END;
- if (tok(p)[1] == '@')
- result = tCVAR;
- else
- result = tIVAR;
- break;
-
- default:
- if (toklast(p) == '!' || toklast(p) == '?') {
- result = tFID;
- }
- else {
- if (p->lstate == EXPR_FNAME) {
- if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
- (!peek(p, '=') || (peek_n(p, '>', 1)))) {
- result = tIDENTIFIER;
- tokadd(p, c);
- tokfix(p);
- }
- else {
- pushback(p, c);
- }
- }
- if (result == 0 && ISUPPER(tok(p)[0])) {
- result = tCONSTANT;
- }
- else {
- result = tIDENTIFIER;
- }
- }
-
- if (IS_LABEL_POSSIBLE()) {
- if (IS_LABEL_SUFFIX(0)) {
- p->lstate = EXPR_BEG;
- nextc(p);
- tokfix(p);
- yylval.id = intern_cstr(tok(p));
- return tLABEL;
- }
- }
- if (p->lstate != EXPR_DOT) {
- const struct kwtable *kw;
-
- /* See if it is a reserved word. */
- kw = mrb_reserved_word(tok(p), toklen(p));
- if (kw) {
- enum mrb_lex_state_enum state = p->lstate;
- p->lstate = kw->state;
- if (state == EXPR_FNAME) {
- yylval.id = intern_cstr(kw->name);
- return kw->id[0];
- }
- if (p->lstate == EXPR_BEG) {
- p->cmd_start = TRUE;
- }
- if (kw->id[0] == keyword_do) {
- if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
- p->lpar_beg = 0;
- p->paren_nest--;
- return keyword_do_LAMBDA;
- }
- if (COND_P()) return keyword_do_cond;
- if (CMDARG_P() && state != EXPR_CMDARG)
- return keyword_do_block;
- if (state == EXPR_ENDARG || state == EXPR_BEG)
- return keyword_do_block;
- return keyword_do;
- }
- if (state == EXPR_BEG || state == EXPR_VALUE)
- return kw->id[0];
- else {
- if (kw->id[0] != kw->id[1])
- p->lstate = EXPR_BEG;
- return kw->id[1];
- }
- }
- }
-
- if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) {
- if (cmd_state) {
- p->lstate = EXPR_CMDARG;
- }
- else {
- p->lstate = EXPR_ARG;
- }
- }
- else if (p->lstate == EXPR_FNAME) {
- p->lstate = EXPR_ENDFN;
- }
- else {
- p->lstate = EXPR_END;
- }
- }
- {
- mrb_sym ident = intern_cstr(tok(p));
-
- yylval.id = ident;
-#if 0
- if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
- p->lstate = EXPR_END;
- }
-#endif
- }
- return result;
- }
-}
-
-static int
-yylex(void *lval, parser_state *p)
-{
- int t;
-
- p->ylval = lval;
- t = parser_yylex(p);
-
- return t;
-}
-
-static void
-parser_init_cxt(parser_state *p, mrbc_context *cxt)
-{
- if (!cxt) return;
- if (cxt->filename) mrb_parser_set_filename(p, cxt->filename);
- if (cxt->lineno) p->lineno = cxt->lineno;
- if (cxt->syms) {
- int i;
-
- p->locals = cons(0,0);
- for (i=0; i<cxt->slen; i++) {
- local_add_f(p, cxt->syms[i]);
- }
- }
- p->capture_errors = cxt->capture_errors;
- if (cxt->partial_hook) {
- p->cxt = cxt;
- }
-}
-
-static void
-parser_update_cxt(parser_state *p, mrbc_context *cxt)
-{
- node *n, *n0;
- int i = 0;
-
- if (!cxt) return;
- if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return;
- n0 = n = p->tree->cdr->car;
- while (n) {
- i++;
- n = n->cdr;
- }
- cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym));
- cxt->slen = i;
- for (i=0, n=n0; n; i++,n=n->cdr) {
- cxt->syms[i] = sym(n->car);
- }
-}
-
-void mrb_codedump_all(mrb_state*, struct RProc*);
-void mrb_parser_dump(mrb_state *mrb, node *tree, int offset);
-
-void
-mrb_parser_parse(parser_state *p, mrbc_context *c)
-{
- struct mrb_jmpbuf buf;
- p->jmp = &buf;
-
- MRB_TRY(p->jmp) {
-
- p->cmd_start = TRUE;
- p->in_def = p->in_single = 0;
- p->nerr = p->nwarn = 0;
- p->lex_strterm = NULL;
-
- parser_init_cxt(p, c);
- yyparse(p);
- if (!p->tree) {
- p->tree = new_nil(p);
- }
- parser_update_cxt(p, c);
- if (c && c->dump_result) {
- mrb_parser_dump(p->mrb, p->tree, 0);
- }
-
- }
- MRB_CATCH(p->jmp) {
- yyerror(p, "memory allocation error");
- p->nerr++;
- p->tree = 0;
- return;
- }
- MRB_END_EXC(p->jmp);
-}
-
-parser_state*
-mrb_parser_new(mrb_state *mrb)
-{
- mrb_pool *pool;
- parser_state *p;
- static const parser_state parser_state_zero = { 0 };
-
- pool = mrb_pool_open(mrb);
- if (!pool) return 0;
- p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state));
- if (!p) return 0;
-
- *p = parser_state_zero;
- p->mrb = mrb;
- p->pool = pool;
-
- p->s = p->send = NULL;
-#ifdef ENABLE_STDIO
- p->f = NULL;
-#endif
-
- p->cmd_start = TRUE;
- p->in_def = p->in_single = 0;
-
- p->capture_errors = FALSE;
- p->lineno = 1;
- p->column = 0;
-#if defined(PARSER_TEST) || defined(PARSER_DEBUG)
- yydebug = 1;
-#endif
-
- p->lex_strterm = NULL;
- p->all_heredocs = p->parsing_heredoc = NULL;
- p->lex_strterm_before_heredoc = NULL;
-
- p->current_filename_index = -1;
- p->filename_table = NULL;
- p->filename_table_length = 0;
-
- return p;
-}
-
-void
-mrb_parser_free(parser_state *p) {
- mrb_pool_close(p->pool);
-}
-
-mrbc_context*
-mrbc_context_new(mrb_state *mrb)
-{
- mrbc_context *c;
-
- c = (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context));
- return c;
-}
-
-void
-mrbc_context_free(mrb_state *mrb, mrbc_context *cxt)
-{
- mrb_free(mrb, cxt->syms);
- mrb_free(mrb, cxt);
-}
-
-const char*
-mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s)
-{
- if (s) {
- int len = strlen(s);
- char *p = (char *)mrb_alloca(mrb, len + 1);
-
- memcpy(p, s, len + 1);
- c->filename = p;
- }
- return c->filename;
-}
-
-void
-mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data)
-{
- c->partial_hook = func;
- c->partial_data = data;
-}
-
-void
-mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
-{
- mrb_sym sym;
- size_t i;
- mrb_sym* new_table;
-
- sym = mrb_intern_cstr(p->mrb, f);
- p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
- p->lineno = (p->filename_table_length > 0)? 0 : 1;
-
- for (i = 0; i < p->filename_table_length; ++i) {
- if (p->filename_table[i] == sym) {
- p->current_filename_index = i;
- return;
- }
- }
-
- p->current_filename_index = p->filename_table_length++;
-
- new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
- if (p->filename_table) {
- memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
- }
- p->filename_table = new_table;
- p->filename_table[p->filename_table_length - 1] = sym;
-}
-
-char const*
-mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
- if (idx >= p->filename_table_length) { return NULL; }
- else {
- return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
- }
-}
-
-#ifdef ENABLE_STDIO
-parser_state*
-mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
-{
- parser_state *p;
-
- p = mrb_parser_new(mrb);
- if (!p) return 0;
- p->s = p->send = NULL;
- p->f = f;
-
- mrb_parser_parse(p, c);
- return p;
-}
-#endif
-
-parser_state*
-mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c)
-{
- parser_state *p;
-
- p = mrb_parser_new(mrb);
- if (!p) return 0;
- p->s = s;
- p->send = s + len;
-
- mrb_parser_parse(p, c);
- return p;
-}
-
-parser_state*
-mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c)
-{
- return mrb_parse_nstring(mrb, s, strlen(s), c);
-}
-
-static mrb_value
-load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
-{
- struct RClass *target = mrb->object_class;
- struct RProc *proc;
- mrb_value v;
- unsigned int keep = 0;
-
- if (!p) {
- return mrb_undef_value();
- }
- if (!p->tree || p->nerr) {
- if (p->capture_errors) {
- char buf[256];
- int n;
-
- n = snprintf(buf, sizeof(buf), "line %d: %s\n",
- p->error_buffer[0].lineno, p->error_buffer[0].message);
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
- mrb_parser_free(p);
- return mrb_undef_value();
- }
- else {
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
- mrb_parser_free(p);
- return mrb_undef_value();
- }
- }
- proc = mrb_generate_code(mrb, p);
- mrb_parser_free(p);
- if (proc == NULL) {
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
- return mrb_undef_value();
- }
- if (c) {
- if (c->dump_result) mrb_codedump_all(mrb, proc);
- if (c->no_exec) return mrb_obj_value(proc);
- if (c->target_class) {
- target = c->target_class;
- }
- keep = c->slen + 1;
- }
- proc->target_class = target;
- if (mrb->c->ci) {
- mrb->c->ci->target_class = target;
- }
- v = mrb_toplevel_run_keep(mrb, proc, keep);
- if (mrb->exc) return mrb_nil_value();
- return v;
-}
-
-#ifdef ENABLE_STDIO
-mrb_value
-mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c)
-{
- return load_exec(mrb, mrb_parse_file(mrb, f, c), c);
-}
-
-mrb_value
-mrb_load_file(mrb_state *mrb, FILE *f)
-{
- return mrb_load_file_cxt(mrb, f, NULL);
-}
-#endif
-
-mrb_value
-mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
-{
- return load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
-}
-
-mrb_value
-mrb_load_nstring(mrb_state *mrb, const char *s, int len)
-{
- return mrb_load_nstring_cxt(mrb, s, len, NULL);
-}
-
-mrb_value
-mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c)
-{
- return mrb_load_nstring_cxt(mrb, s, strlen(s), c);
-}
-
-mrb_value
-mrb_load_string(mrb_state *mrb, const char *s)
-{
- return mrb_load_string_cxt(mrb, s, NULL);
-}
-
-#ifdef ENABLE_STDIO
-
-static void
-dump_prefix(int offset)
-{
- while (offset--) {
- putc(' ', stdout);
- putc(' ', stdout);
- }
-}
-
-static void
-dump_recur(mrb_state *mrb, node *tree, int offset)
-{
- while (tree) {
- mrb_parser_dump(mrb, tree->car, offset);
- tree = tree->cdr;
- }
-}
-
-#endif
-
-void
-mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
-{
-#ifdef ENABLE_STDIO
- int n;
-
- if (!tree) return;
- again:
- dump_prefix(offset);
- n = (int)(intptr_t)tree->car;
- tree = tree->cdr;
- switch (n) {
- case NODE_BEGIN:
- printf("NODE_BEGIN:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_RESCUE:
- printf("NODE_RESCUE:\n");
- if (tree->car) {
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- }
- tree = tree->cdr;
- if (tree->car) {
- node *n2 = tree->car;
-
- dump_prefix(offset+1);
- printf("rescue:\n");
- while (n2) {
- node *n3 = n2->car;
- if (n3->car) {
- dump_prefix(offset+2);
- printf("handle classes:\n");
- dump_recur(mrb, n3->car, offset+3);
- }
- if (n3->cdr->car) {
- dump_prefix(offset+2);
- printf("exc_var:\n");
- mrb_parser_dump(mrb, n3->cdr->car, offset+3);
- }
- if (n3->cdr->cdr->car) {
- dump_prefix(offset+2);
- printf("rescue body:\n");
- mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3);
- }
- n2 = n2->cdr;
- }
- }
- tree = tree->cdr;
- if (tree->car) {
- dump_prefix(offset+1);
- printf("else:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- }
- break;
-
- case NODE_ENSURE:
- printf("NODE_ENSURE:\n");
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(offset+1);
- printf("ensure:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr, offset+2);
- break;
-
- case NODE_LAMBDA:
- printf("NODE_BLOCK:\n");
- goto block;
-
- case NODE_BLOCK:
- block:
- printf("NODE_BLOCK:\n");
- tree = tree->cdr;
- if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
- }
- }
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- break;
-
- case NODE_IF:
- printf("NODE_IF:\n");
- dump_prefix(offset+1);
- printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(offset+1);
- printf("then:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- if (tree->cdr->cdr->car) {
- dump_prefix(offset+1);
- printf("else:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2);
- }
- break;
-
- case NODE_AND:
- printf("NODE_AND:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
- break;
-
- case NODE_OR:
- printf("NODE_OR:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
- break;
-
- case NODE_CASE:
- printf("NODE_CASE:\n");
- if (tree->car) {
- mrb_parser_dump(mrb, tree->car, offset+1);
- }
- tree = tree->cdr;
- while (tree) {
- dump_prefix(offset+1);
- printf("case:\n");
- dump_recur(mrb, tree->car->car, offset+2);
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->car->cdr, offset+2);
- tree = tree->cdr;
- }
- break;
-
- case NODE_WHILE:
- printf("NODE_WHILE:\n");
- dump_prefix(offset+1);
- printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
- case NODE_UNTIL:
- printf("NODE_UNTIL:\n");
- dump_prefix(offset+1);
- printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
- case NODE_FOR:
- printf("NODE_FOR:\n");
- dump_prefix(offset+1);
- printf("var:\n");
- {
- node *n2 = tree->car;
-
- if (n2->car) {
- dump_prefix(offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("rest:\n");
- mrb_parser_dump(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- }
- }
- }
- tree = tree->cdr;
- dump_prefix(offset+1);
- printf("in:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- tree = tree->cdr;
- dump_prefix(offset+1);
- printf("do:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- break;
-
- case NODE_SCOPE:
- printf("NODE_SCOPE:\n");
- {
- node *n2 = tree->car;
-
- if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(offset+1);
- printf("local variables:\n");
- dump_prefix(offset+2);
- while (n2) {
- if (n2->car) {
- if (n2 != tree->car) printf(", ");
- printf("%s", mrb_sym2name(mrb, sym(n2->car)));
- }
- n2 = n2->cdr;
- }
- printf("\n");
- }
- }
- tree = tree->cdr;
- offset++;
- goto again;
-
- case NODE_FCALL:
- case NODE_CALL:
- printf("NODE_CALL:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(offset+1);
- printf("method='%s' (%d)\n",
- mrb_sym2name(mrb, sym(tree->cdr->car)),
- (int)(intptr_t)tree->cdr->car);
- tree = tree->cdr->cdr->car;
- if (tree) {
- dump_prefix(offset+1);
- printf("args:\n");
- dump_recur(mrb, tree->car, offset+2);
- if (tree->cdr) {
- dump_prefix(offset+1);
- printf("block:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- }
- }
- break;
-
- case NODE_DOT2:
- printf("NODE_DOT2:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
- break;
-
- case NODE_DOT3:
- printf("NODE_DOT3:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
- break;
-
- case NODE_COLON2:
- printf("NODE_COLON2:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr)));
- break;
-
- case NODE_COLON3:
- printf("NODE_COLON3:\n");
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_ARRAY:
- printf("NODE_ARRAY:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_HASH:
- printf("NODE_HASH:\n");
- while (tree) {
- dump_prefix(offset+1);
- printf("key:\n");
- mrb_parser_dump(mrb, tree->car->car, offset+2);
- dump_prefix(offset+1);
- printf("value:\n");
- mrb_parser_dump(mrb, tree->car->cdr, offset+2);
- tree = tree->cdr;
- }
- break;
-
- case NODE_SPLAT:
- printf("NODE_SPLAT:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_ASGN:
- printf("NODE_ASGN:\n");
- dump_prefix(offset+1);
- printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(offset+1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
- case NODE_MASGN:
- printf("NODE_MASGN:\n");
- dump_prefix(offset+1);
- printf("mlhs:\n");
- {
- node *n2 = tree->car;
-
- if (n2->car) {
- dump_prefix(offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("rest:\n");
- if (n2->car == (node*)-1) {
- dump_prefix(offset+2);
- printf("(empty)\n");
- }
- else {
- mrb_parser_dump(mrb, n2->car, offset+3);
- }
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- }
- }
- }
- dump_prefix(offset+1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
- case NODE_OP_ASGN:
- printf("NODE_OP_ASGN:\n");
- dump_prefix(offset+1);
- printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- tree = tree->cdr;
- dump_prefix(offset+1);
- printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
- tree = tree->cdr;
- mrb_parser_dump(mrb, tree->car, offset+1);
- break;
-
- case NODE_SUPER:
- printf("NODE_SUPER:\n");
- if (tree) {
- dump_prefix(offset+1);
- printf("args:\n");
- dump_recur(mrb, tree->car, offset+2);
- if (tree->cdr) {
- dump_prefix(offset+1);
- printf("block:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- }
- }
- break;
-
- case NODE_ZSUPER:
- printf("NODE_ZSUPER\n");
- break;
-
- case NODE_RETURN:
- printf("NODE_RETURN:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_YIELD:
- printf("NODE_YIELD:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_BREAK:
- printf("NODE_BREAK:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_NEXT:
- printf("NODE_NEXT:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_REDO:
- printf("NODE_REDO\n");
- break;
-
- case NODE_RETRY:
- printf("NODE_RETRY\n");
- break;
-
- case NODE_LVAR:
- printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_GVAR:
- printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_IVAR:
- printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_CVAR:
- printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_CONST:
- printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_MATCH:
- printf("NODE_MATCH:\n");
- dump_prefix(offset + 1);
- printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset + 2);
- dump_prefix(offset + 1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset + 2);
- break;
-
- case NODE_BACK_REF:
- printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree);
- break;
-
- case NODE_NTH_REF:
- printf("NODE_NTH_REF: $%d\n", (int)(intptr_t)tree);
- break;
-
- case NODE_ARG:
- printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_BLOCK_ARG:
- printf("NODE_BLOCK_ARG:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_INT:
- printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car);
- break;
-
- case NODE_FLOAT:
- printf("NODE_FLOAT %s\n", (char*)tree);
- break;
-
- case NODE_NEGATE:
- printf("NODE_NEGATE\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_STR:
- printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
- break;
-
- case NODE_DSTR:
- printf("NODE_DSTR\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_XSTR:
- printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
- break;
-
- case NODE_DXSTR:
- printf("NODE_DXSTR\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_REGX:
- printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr);
- break;
-
- case NODE_DREGX:
- printf("NODE_DREGX\n");
- dump_recur(mrb, tree->car, offset+1);
- dump_prefix(offset);
- printf("tail: %s\n", (char*)tree->cdr->cdr->car);
- dump_prefix(offset);
- printf("opt: %s\n", (char*)tree->cdr->cdr->cdr);
- break;
-
- case NODE_SYM:
- printf("NODE_SYM :%s\n", mrb_sym2name(mrb, sym(tree)));
- break;
-
- case NODE_SELF:
- printf("NODE_SELF\n");
- break;
-
- case NODE_NIL:
- printf("NODE_NIL\n");
- break;
-
- case NODE_TRUE:
- printf("NODE_TRUE\n");
- break;
-
- case NODE_FALSE:
- printf("NODE_FALSE\n");
- break;
-
- case NODE_ALIAS:
- printf("NODE_ALIAS %s %s:\n",
- mrb_sym2name(mrb, sym(tree->car)),
- mrb_sym2name(mrb, sym(tree->cdr)));
- break;
-
- case NODE_UNDEF:
- printf("NODE_UNDEF");
- {
- node *t = tree;
- while (t) {
- printf(" %s", mrb_sym2name(mrb, sym(t->car)));
- t = t->cdr;
- }
- }
- printf(":\n");
- break;
-
- case NODE_CLASS:
- printf("NODE_CLASS:\n");
- if (tree->car->car == (node*)0) {
- dump_prefix(offset+1);
- printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- else if (tree->car->car == (node*)1) {
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- else {
- mrb_parser_dump(mrb, tree->car->car, offset+1);
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- if (tree->cdr->car) {
- dump_prefix(offset+1);
- printf("super:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- }
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2);
- break;
-
- case NODE_MODULE:
- printf("NODE_MODULE:\n");
- if (tree->car->car == (node*)0) {
- dump_prefix(offset+1);
- printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- else if (tree->car->car == (node*)1) {
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- else {
- mrb_parser_dump(mrb, tree->car->car, offset+1);
- dump_prefix(offset+1);
- printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
- }
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
- break;
-
- case NODE_SCLASS:
- printf("NODE_SCLASS:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
- break;
-
- case NODE_DEF:
- printf("NODE_DEF:\n");
- dump_prefix(offset+1);
- printf("%s\n", mrb_sym2name(mrb, sym(tree->car)));
- tree = tree->cdr;
- {
- node *n2 = tree->car;
-
- if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(offset+1);
- printf("local variables:\n");
- dump_prefix(offset+2);
- while (n2) {
- if (n2->car) {
- if (n2 != tree->car) printf(", ");
- printf("%s", mrb_sym2name(mrb, sym(n2->car)));
- }
- n2 = n2->cdr;
- }
- printf("\n");
- }
- }
- tree = tree->cdr;
- if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
- }
- }
- mrb_parser_dump(mrb, tree->cdr->car, offset+1);
- break;
-
- case NODE_SDEF:
- printf("NODE_SDEF:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- tree = tree->cdr;
- dump_prefix(offset+1);
- printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
- tree = tree->cdr->cdr;
- if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n) {
- dump_prefix(offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
- }
- }
- tree = tree->cdr;
- mrb_parser_dump(mrb, tree->car, offset+1);
- break;
-
- case NODE_POSTEXE:
- printf("NODE_POSTEXE:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_HEREDOC:
- printf("NODE_HEREDOC:\n");
- mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
- break;
-
- default:
- printf("node type: %d (0x%x)\n", (int)n, (int)n);
- break;
- }
-#endif
-}
diff --git a/src/pool.c b/src/pool.c
index 4d8c42dd1..18f66fc27 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -7,7 +7,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
-#include "mruby.h"
+#include <mruby.h>
/* configuration section */
/* allocated memory address should be multiple of POOL_ALIGNMENT */
@@ -47,7 +47,7 @@ struct mrb_pool {
# define ALIGN_PADDING(x) (0)
#endif
-mrb_pool*
+MRB_API mrb_pool*
mrb_pool_open(mrb_state *mrb)
{
mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool));
@@ -60,7 +60,7 @@ mrb_pool_open(mrb_state *mrb)
return pool;
}
-void
+MRB_API void
mrb_pool_close(mrb_pool *pool)
{
struct mrb_pool_page *page, *tmp;
@@ -91,7 +91,7 @@ page_alloc(mrb_pool *pool, size_t len)
return page;
}
-void*
+MRB_API void*
mrb_pool_alloc(mrb_pool *pool, size_t len)
{
struct mrb_pool_page *page;
@@ -119,7 +119,7 @@ mrb_pool_alloc(mrb_pool *pool, size_t len)
return page->last;
}
-mrb_bool
+MRB_API mrb_bool
mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len)
{
struct mrb_pool_page *page;
@@ -140,7 +140,7 @@ mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len)
return FALSE;
}
-void*
+MRB_API void*
mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen)
{
struct mrb_pool_page *page;
@@ -166,6 +166,9 @@ mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen)
page = page->next;
}
np = mrb_pool_alloc(pool, newlen);
+ if (np == NULL) {
+ return NULL;
+ }
memcpy(np, p, oldlen);
return np;
}
diff --git a/src/print.c b/src/print.c
index f4ed85601..03b5eadfa 100644
--- a/src/print.c
+++ b/src/print.c
@@ -4,66 +4,44 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#ifndef MRB_DISABLE_STDIO
static void
-printstr(mrb_state *mrb, mrb_value obj)
+printstr(mrb_value obj, FILE *stream)
{
-#ifdef ENABLE_STDIO
- char *s;
- int len;
-
if (mrb_string_p(obj)) {
- s = RSTRING_PTR(obj);
- len = RSTRING_LEN(obj);
- fwrite(s, len, 1, stdout);
+ fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stream);
+ putc('\n', stream);
}
-#endif
}
+#else
+# define printstr(obj, stream) (void)0
+#endif
-void
+MRB_API void
mrb_p(mrb_state *mrb, mrb_value obj)
{
-#ifdef ENABLE_STDIO
- obj = mrb_funcall(mrb, obj, "inspect", 0);
- printstr(mrb, obj);
- putc('\n', stdout);
-#endif
+ printstr(mrb_inspect(mrb, obj), stdout);
}
-void
+MRB_API void
mrb_print_error(mrb_state *mrb)
{
-#ifdef ENABLE_STDIO
- mrb_value s;
-
mrb_print_backtrace(mrb);
- s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
- if (mrb_string_p(s)) {
- fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr);
- putc('\n', stderr);
- }
-#endif
+ printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr);
}
-void
+MRB_API void
mrb_show_version(mrb_state *mrb)
{
- mrb_value msg;
-
- msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION"));
- printstr(mrb, msg);
- printstr(mrb, mrb_str_new_lit(mrb, "\n"));
+ printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION")), stdout);
}
-void
+MRB_API void
mrb_show_copyright(mrb_state *mrb)
{
- mrb_value msg;
-
- msg = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT"));
- printstr(mrb, msg);
- printstr(mrb, mrb_str_new_lit(mrb, "\n"));
+ printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")), stdout);
}
diff --git a/src/proc.c b/src/proc.c
index d4fe86680..34037b167 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -4,10 +4,10 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/proc.h"
-#include "mruby/opcode.h"
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/opcode.h>
static mrb_code call_iseq[] = {
MKOP_A(OP_CALL, 0),
@@ -34,17 +34,27 @@ mrb_proc_new(mrb_state *mrb, mrb_irep *irep)
return p;
}
-static inline void
+static struct REnv*
+env_new(mrb_state *mrb, int nlocals)
+{
+ struct REnv *e;
+
+ e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
+ MRB_SET_ENV_STACK_LEN(e, nlocals);
+ e->mid = mrb->c->ci->mid;
+ e->cioff = mrb->c->ci - mrb->c->cibase;
+ e->stack = mrb->c->stack;
+
+ return e;
+}
+
+static void
closure_setup(mrb_state *mrb, struct RProc *p, int nlocals)
{
struct REnv *e;
if (!mrb->c->ci->env) {
- e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env);
- MRB_ENV_STACK_LEN(e)= (unsigned int)nlocals;
- e->mid = mrb->c->ci->mid;
- e->cioff = mrb->c->ci - mrb->c->cibase;
- e->stack = mrb->c->stack;
+ e = env_new(mrb, nlocals);
mrb->c->ci->env = e;
}
else {
@@ -62,7 +72,7 @@ mrb_closure_new(mrb_state *mrb, mrb_irep *irep)
return p;
}
-struct RProc *
+MRB_API struct RProc *
mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
{
struct RProc *p;
@@ -75,16 +85,57 @@ mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func)
return p;
}
-struct RProc *
-mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
+MRB_API struct RProc *
+mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv)
{
struct RProc *p = mrb_proc_new_cfunc(mrb, func);
-
- closure_setup(mrb, p, nlocals);
+ struct REnv *e;
+ int i;
+
+ p->env = e = env_new(mrb, argc);
+ mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env);
+ MRB_ENV_UNSHARE_STACK(e);
+ e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc);
+ if (argv) {
+ for (i = 0; i < argc; ++i) {
+ e->stack[i] = argv[i];
+ }
+ }
+ else {
+ for (i = 0; i < argc; ++i) {
+ SET_NIL_VALUE(e->stack[i]);
+ }
+ }
return p;
}
-void
+MRB_API struct RProc *
+mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals)
+{
+ return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL);
+}
+
+MRB_API mrb_value
+mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx)
+{
+ struct RProc *p = mrb->c->ci->proc;
+ struct REnv *e = p->env;
+
+ if (!MRB_PROC_CFUNC_P(p)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc.");
+ }
+ if (!e) {
+ mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv.");
+ }
+ if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)",
+ mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e)));
+ }
+
+ return e->stack[idx];
+}
+
+MRB_API void
mrb_proc_copy(struct RProc *a, struct RProc *b)
{
a->flags = b->flags;
@@ -149,13 +200,25 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
{
struct RProc *p = mrb_proc_ptr(self);
mrb_code *iseq = mrb_proc_iseq(mrb, p);
- mrb_aspec aspec = GETARG_Ax(*iseq);
- int ma, ra, pa, arity;
+ mrb_aspec aspec;
+ int ma, op, ra, pa, arity;
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ /* TODO cfunc aspec not implemented yet */
+ return mrb_fixnum_value(-1);
+ }
+
+ /* arity is depend on OP_ENTER */
+ if (GET_OPCODE(*iseq) != OP_ENTER) {
+ return mrb_fixnum_value(0);
+ }
+ aspec = GETARG_Ax(*iseq);
ma = MRB_ASPEC_REQ(aspec);
+ op = MRB_ASPEC_OPT(aspec);
ra = MRB_ASPEC_REST(aspec);
pa = MRB_ASPEC_POST(aspec);
- arity = ra ? -(ma + pa + 1) : ma + pa;
+ arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa;
return mrb_fixnum_value(arity);
}
@@ -179,6 +242,9 @@ proc_lambda(mrb_state *mrb, mrb_value self)
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
}
+ if (mrb_type(blk) != MRB_TT_PROC) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc");
+ }
p = mrb_proc_ptr(blk);
if (!MRB_PROC_STRICT_P(p)) {
struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c);
@@ -201,9 +267,6 @@ mrb_init_proc(mrb_state *mrb)
call_irep->iseq = call_iseq;
call_irep->ilen = 1;
- mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class); /* 15.2.17 */
- MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC);
-
mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE());
mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE());
diff --git a/src/range.c b/src/range.c
index 53000e660..bc8b11419 100644
--- a/src/range.c
+++ b/src/range.c
@@ -4,11 +4,11 @@
** See Copyright Notice in mruby.h
*/
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/range.h"
-#include "mruby/string.h"
-#include "mruby/array.h"
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/array.h>
#define RANGE_CLASS (mrb_class_get(mrb, "Range"))
@@ -33,7 +33,7 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b)
}
}
-mrb_value
+MRB_API mrb_value
mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
{
struct RRange *r;
@@ -234,16 +234,16 @@ mrb_range_include(mrb_state *mrb, mrb_value range)
return mrb_bool_value(include_p);
}
-mrb_bool
+static mrb_bool
range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
{
- mrb_int beg, end, b, e;
+ mrb_int beg, end;
struct RRange *r = mrb_range_ptr(range);
if (mrb_type(range) != MRB_TT_RANGE) return FALSE;
- beg = b = mrb_int(mrb, r->edges->beg);
- end = e = mrb_int(mrb, r->edges->end);
+ beg = mrb_int(mrb, r->edges->beg);
+ end = mrb_int(mrb, r->edges->end);
if (beg < 0) {
beg += len;
@@ -266,7 +266,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb
return TRUE;
}
-mrb_bool
+MRB_API mrb_bool
mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len)
{
return range_beg_len(mrb, range, begp, lenp, len, TRUE);
@@ -290,7 +290,7 @@ range_to_s(mrb_state *mrb, mrb_value range)
str2 = mrb_obj_as_string(mrb, r->edges->end);
str = mrb_str_dup(mrb, str);
mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
- mrb_str_append(mrb, str, str2);
+ mrb_str_cat_str(mrb, str, str2);
return str;
}
@@ -315,7 +315,7 @@ range_inspect(mrb_state *mrb, mrb_value range)
str2 = mrb_inspect(mrb, r->edges->end);
str = mrb_str_dup(mrb, str);
mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
- mrb_str_append(mrb, str, str2);
+ mrb_str_cat_str(mrb, str, str2);
return str;
}
diff --git a/src/state.c b/src/state.c
index 3e82a159d..c8c0658e4 100644
--- a/src/state.c
+++ b/src/state.c
@@ -6,14 +6,17 @@
#include <stdlib.h>
#include <string.h>
-#include "mruby.h"
-#include "mruby/irep.h"
-#include "mruby/variable.h"
-#include "mruby/debug.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/irep.h>
+#include <mruby/variable.h>
+#include <mruby/debug.h>
+#include <mruby/string.h>
-void mrb_init_heap(mrb_state*);
void mrb_init_core(mrb_state*);
+void mrb_init_mrbgems(mrb_state*);
+
+void mrb_gc_init(mrb_state*, mrb_gc *gc);
+void mrb_gc_destroy(mrb_state*, mrb_gc *gc);
static mrb_value
inspect_main(mrb_state *mrb, mrb_value mod)
@@ -21,42 +24,33 @@ inspect_main(mrb_state *mrb, mrb_value mod)
return mrb_str_new_lit(mrb, "main");
}
-mrb_state*
-mrb_open_allocf(mrb_allocf f, void *ud)
+MRB_API mrb_state*
+mrb_open_core(mrb_allocf f, void *ud)
{
static const mrb_state mrb_state_zero = { 0 };
static const struct mrb_context mrb_context_zero = { 0 };
mrb_state *mrb;
-#ifdef MRB_NAN_BOXING
- mrb_static_assert(sizeof(void*) == 4, "when using NaN boxing sizeof pointer must be 4 byte");
-#endif
-
mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud);
if (mrb == NULL) return NULL;
*mrb = mrb_state_zero;
- mrb->ud = ud;
+ mrb->allocf_ud = ud;
mrb->allocf = f;
- mrb->current_white_part = MRB_GC_WHITE_A;
mrb->atexit_stack_len = 0;
-#ifndef MRB_GC_FIXED_ARENA
- mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
- mrb->arena_capa = MRB_GC_ARENA_SIZE;
-#endif
-
- mrb_init_heap(mrb);
+ mrb_gc_init(mrb, &mrb->gc);
mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
*mrb->c = mrb_context_zero;
mrb->root_c = mrb->c;
+
mrb_init_core(mrb);
return mrb;
}
-static void*
-allocf(mrb_state *mrb, void *p, size_t size, void *ud)
+void*
+mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud)
{
if (size == 0) {
free(p);
@@ -72,7 +66,7 @@ struct alloca_header {
char buf[];
};
-void*
+MRB_API void*
mrb_alloca(mrb_state *mrb, size_t size)
{
struct alloca_header *p;
@@ -99,16 +93,31 @@ mrb_alloca_free(mrb_state *mrb)
}
}
-mrb_state*
+MRB_API mrb_state*
mrb_open(void)
{
- mrb_state *mrb = mrb_open_allocf(allocf, NULL);
+ mrb_state *mrb = mrb_open_allocf(mrb_default_allocf, NULL);
+
+ return mrb;
+}
+
+MRB_API mrb_state*
+mrb_open_allocf(mrb_allocf f, void *ud)
+{
+ mrb_state *mrb = mrb_open_core(f, ud);
+
+ if (mrb == NULL) {
+ return NULL;
+ }
+#ifndef DISABLE_GEMS
+ mrb_init_mrbgems(mrb);
+ mrb_gc_arena_restore(mrb, 0);
+#endif
return mrb;
}
void mrb_free_symtbl(mrb_state *mrb);
-void mrb_free_heap(mrb_state *mrb);
void
mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
@@ -168,7 +177,7 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
ns->tt = MRB_TT_STRING;
ns->c = mrb->string_class;
- if (s->flags & MRB_STR_NOFREE) {
+ if (RSTR_NOFREE_P(s)) {
ns->flags = MRB_STR_NOFREE;
ns->as.heap.ptr = s->as.heap.ptr;
ns->as.heap.len = s->as.heap.len;
@@ -176,9 +185,9 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
}
else {
ns->flags = 0;
- if (s->flags & MRB_STR_EMBED) {
+ if (RSTR_EMBED_P(s)) {
ptr = s->as.ary;
- len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT);
+ len = RSTR_EMBED_LEN(s);
}
else {
ptr = s->as.heap.ptr;
@@ -186,9 +195,8 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
}
if (len < RSTRING_EMBED_LEN_MAX) {
- ns->flags |= MRB_STR_EMBED;
- ns->flags &= ~MRB_STR_EMBED_LEN_MASK;
- ns->flags |= (size_t)len << MRB_STR_EMBED_LEN_SHIFT;
+ RSTR_SET_EMBED_FLAG(ns);
+ RSTR_SET_EMBED_LEN(ns, len);
if (ptr) {
memcpy(ns->as.ary, ptr, len);
}
@@ -207,7 +215,7 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
return mrb_obj_value(ns);
}
-void
+MRB_API void
mrb_free_context(mrb_state *mrb, struct mrb_context *c)
{
if (!c) return;
@@ -218,9 +226,10 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c)
mrb_free(mrb, c);
}
-void
+MRB_API void
mrb_close(mrb_state *mrb)
{
+ if (!mrb) return;
if (mrb->atexit_stack_len > 0) {
mrb_int i;
for (i = mrb->atexit_stack_len; i > 0; --i) {
@@ -235,15 +244,12 @@ mrb_close(mrb_state *mrb)
mrb_gc_free_gv(mrb);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
- mrb_free_heap(mrb);
mrb_alloca_free(mrb);
-#ifndef MRB_GC_FIXED_ARENA
- mrb_free(mrb, mrb->arena);
-#endif
+ mrb_gc_destroy(mrb, &mrb->gc);
mrb_free(mrb, mrb);
}
-mrb_irep*
+MRB_API mrb_irep*
mrb_add_irep(mrb_state *mrb)
{
static const mrb_irep mrb_irep_zero = { 0 };
@@ -256,7 +262,7 @@ mrb_add_irep(mrb_state *mrb)
return irep;
}
-mrb_value
+MRB_API mrb_value
mrb_top_self(mrb_state *mrb)
{
if (!mrb->top_self) {
@@ -267,7 +273,7 @@ mrb_top_self(mrb_state *mrb)
return mrb_obj_value(mrb->top_self);
}
-void
+MRB_API void
mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f)
{
#ifdef MRB_FIXED_STATE_ATEXIT_STACK
diff --git a/src/string.c b/src/string.c
index 6570c89fb..6664eabd6 100644
--- a/src/string.c
+++ b/src/string.c
@@ -4,20 +4,21 @@
** See Copyright Notice in mruby.h
*/
-#include <ctype.h>
+#ifdef _MSC_VER
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
#include <float.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/range.h"
-#include "mruby/string.h"
-#include "mruby/re.h"
-
-const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/re.h>
typedef struct mrb_shared_string {
mrb_bool nofree : 1;
@@ -26,129 +27,39 @@ typedef struct mrb_shared_string {
mrb_int len;
} mrb_shared_string;
-static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
-static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
-
-mrb_int
-mrb_str_strlen(mrb_state *mrb, struct RString *s)
-{
- mrb_int i, max = RSTR_LEN(s);
- char *p = RSTR_PTR(s);
-
- if (!p) return 0;
- for (i=0; i<max; i++) {
- if (p[i] == '\0') {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
- }
- }
- return max;
-}
-
-static inline void
-resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
-{
- if (RSTR_EMBED_P(s)) {
- if (RSTRING_EMBED_LEN_MAX < capacity) {
- char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
- const mrb_int len = RSTR_EMBED_LEN(s);
- memcpy(tmp, s->as.ary, len);
- RSTR_UNSET_EMBED_FLAG(s);
- s->as.heap.ptr = tmp;
- s->as.heap.len = len;
- s->as.heap.aux.capa = capacity;
- }
- }
- else {
- s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
- s->as.heap.aux.capa = capacity;
- }
-}
+const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-static void
-str_decref(mrb_state *mrb, mrb_shared_string *shared)
-{
- shared->refcnt--;
- if (shared->refcnt == 0) {
- if (!shared->nofree) {
- mrb_free(mrb, shared->ptr);
- }
- mrb_free(mrb, shared);
- }
-}
+#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
-void
-mrb_str_modify(mrb_state *mrb, struct RString *s)
+static struct RString*
+str_new_static(mrb_state *mrb, const char *p, size_t len)
{
- if (RSTR_SHARED_P(s)) {
- mrb_shared_string *shared = s->as.heap.aux.shared;
-
- if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
- s->as.heap.ptr = shared->ptr;
- s->as.heap.aux.capa = shared->len;
- RSTR_PTR(s)[s->as.heap.len] = '\0';
- mrb_free(mrb, shared);
- }
- else {
- char *ptr, *p;
- mrb_int len;
-
- p = RSTR_PTR(s);
- len = s->as.heap.len;
- ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
- if (p) {
- memcpy(ptr, p, len);
- }
- ptr[len] = '\0';
- s->as.heap.ptr = ptr;
- s->as.heap.aux.capa = len;
- str_decref(mrb, shared);
- }
- RSTR_UNSET_SHARED_FLAG(s);
- return;
- }
- if (RSTR_NOFREE_P(s)) {
- char *p = s->as.heap.ptr;
+ struct RString *s;
- s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
- if (p) {
- memcpy(RSTR_PTR(s), p, s->as.heap.len);
- }
- RSTR_PTR(s)[s->as.heap.len] = '\0';
- s->as.heap.aux.capa = s->as.heap.len;
- RSTR_UNSET_NOFREE_FLAG(s);
- return;
+ if (len >= MRB_INT_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
-}
-
-mrb_value
-mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
-{
- mrb_int slen;
- struct RString *s = mrb_str_ptr(str);
+ s = mrb_obj_alloc_string(mrb);
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = 0; /* nofree */
+ s->as.heap.ptr = (char *)p;
+ s->flags = MRB_STR_NOFREE;
- mrb_str_modify(mrb, s);
- slen = RSTR_LEN(s);
- if (len != slen) {
- if (slen < len || slen - len > 256) {
- resize_capa(mrb, s, len);
- }
- RSTR_SET_LEN(s, len);
- RSTR_PTR(s)[len] = '\0'; /* sentinel */
- }
- return str;
+ return s;
}
-#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class))
-
static struct RString*
str_new(mrb_state *mrb, const char *p, size_t len)
{
struct RString *s;
+ if (p && mrb_ro_data_p(p)) {
+ return str_new_static(mrb, p, len);
+ }
s = mrb_obj_alloc_string(mrb);
if (len < RSTRING_EMBED_LEN_MAX) {
RSTR_SET_EMBED_FLAG(s);
- RSTR_SET_EMBED_LEN(s,len);
+ RSTR_SET_EMBED_LEN(s, len);
if (p) {
memcpy(s->as.ary, p, len);
}
@@ -167,7 +78,7 @@ str_new(mrb_state *mrb, const char *p, size_t len)
return s;
}
-static void
+static inline void
str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj)
{
s->c = mrb_str_ptr(obj)->c;
@@ -186,7 +97,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str)
# define MRB_STR_BUF_MIN_SIZE 128
#endif
-mrb_value
+MRB_API mrb_value
mrb_str_buf_new(mrb_state *mrb, size_t capa)
{
struct RString *s;
@@ -207,6 +118,26 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
return mrb_obj_value(s);
}
+static inline void
+resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
+{
+ if (RSTR_EMBED_P(s)) {
+ if (RSTRING_EMBED_LEN_MAX < capacity) {
+ char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
+ const mrb_int len = RSTR_EMBED_LEN(s);
+ memcpy(tmp, s->as.ary, len);
+ RSTR_UNSET_EMBED_FLAG(s);
+ s->as.heap.ptr = tmp;
+ s->as.heap.len = len;
+ s->as.heap.aux.capa = capacity;
+ }
+ }
+ else {
+ s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
+ s->as.heap.aux.capa = capacity;
+ }
+}
+
static void
str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
{
@@ -248,7 +179,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
RSTR_PTR(s)[total] = '\0'; /* sentinel */
}
-mrb_value
+MRB_API mrb_value
mrb_str_new(mrb_state *mrb, const char *p, size_t len)
{
return mrb_obj_value(str_new(mrb, p, len));
@@ -261,7 +192,7 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len)
* Returns a new string object containing a copy of <i>str</i>.
*/
-mrb_value
+MRB_API mrb_value
mrb_str_new_cstr(mrb_state *mrb, const char *p)
{
struct RString *s;
@@ -279,20 +210,23 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p)
return mrb_obj_value(s);
}
-mrb_value
+MRB_API mrb_value
mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
{
- struct RString *s;
+ struct RString *s = str_new_static(mrb, p, len);
+ return mrb_obj_value(s);
+}
- if (len >= MRB_INT_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
+static void
+str_decref(mrb_state *mrb, mrb_shared_string *shared)
+{
+ shared->refcnt--;
+ if (shared->refcnt == 0) {
+ if (!shared->nofree) {
+ mrb_free(mrb, shared->ptr);
+ }
+ mrb_free(mrb, shared);
}
- s = mrb_obj_alloc_string(mrb);
- s->as.heap.len = len;
- s->as.heap.aux.capa = 0; /* nofree */
- s->as.heap.ptr = (char *)p;
- s->flags = MRB_STR_NOFREE;
- return mrb_obj_value(s);
}
void
@@ -306,20 +240,126 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str)
mrb_free(mrb, str->as.heap.ptr);
}
-char *
-mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
+#ifdef MRB_UTF8_STRING
+static const char utf8len_codepage[256] =
{
- struct RString *s;
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,
+};
- if (!mrb_string_p(str0)) {
- mrb_raise(mrb, E_TYPE_ERROR, "expected String");
+static mrb_int
+utf8len(const char* p, const char* e)
+{
+ mrb_int len;
+ mrb_int i;
+
+ len = utf8len_codepage[(unsigned char)*p];
+ if (p + len > e) return 1;
+ for (i = 1; i < len; ++i)
+ if ((p[i] & 0xc0) != 0x80)
+ return 1;
+ return len;
+}
+
+static mrb_int
+utf8_strlen(mrb_value str, mrb_int len)
+{
+ mrb_int total = 0;
+ char* p = RSTRING_PTR(str);
+ char* e = p;
+ e += len < 0 ? RSTRING_LEN(str) : len;
+ while (p<e) {
+ p += utf8len(p, e);
+ total++;
}
+ return total;
+}
- s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
- if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1)
+
+/* map character index to byte offset index */
+static mrb_int
+chars2bytes(mrb_value s, mrb_int off, mrb_int idx)
+{
+ mrb_int i, b, n;
+ const char *p = RSTRING_PTR(s) + off;
+ const char *e = RSTRING_END(s);
+
+ for (b=i=0; p<e && i<idx; i++) {
+ n = utf8len(p, e);
+ b += n;
+ p += n;
}
- return RSTR_PTR(s);
+ return b;
+}
+
+/* map byte offset to character index */
+static mrb_int
+bytes2chars(char *p, mrb_int bi)
+{
+ mrb_int i, b, n;
+
+ for (b=i=0; b<bi; i++) {
+ n = utf8len(p, p+bi);
+ b += n;
+ p += n;
+ }
+ return i;
+}
+
+#else
+#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
+#define chars2bytes(p, off, ci) (ci)
+#define bytes2chars(p, bi) (bi)
+#endif
+
+static inline mrb_int
+mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n)
+{
+ const unsigned char *x = xs, *xe = xs + m;
+ const unsigned char *y = ys;
+ int i, qstable[256];
+
+ /* Preprocessing */
+ for (i = 0; i < 256; ++i)
+ qstable[i] = m + 1;
+ for (; x < xe; ++x)
+ qstable[*x] = xe - x;
+ /* Searching */
+ for (; y + m <= ys + n; y += *(qstable + y[m])) {
+ if (*xs == *y && memcmp(xs, y, m) == 0)
+ return y - ys;
+ }
+ return -1;
+}
+
+static mrb_int
+mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
+{
+ const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0;
+
+ if (m > n) return -1;
+ else if (m == n) {
+ return memcmp(x0, y0, m) == 0 ? 0 : -1;
+ }
+ else if (m < 1) {
+ return 0;
+ }
+ else if (m == 1) {
+ const unsigned char *ys = y, *ye = ys + n;
+ for (; y < ye; ++y) {
+ if (*x == *y)
+ return y - ys;
+ }
+ return -1;
+ }
+ return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
}
static void
@@ -360,18 +400,336 @@ str_make_shared(mrb_state *mrb, struct RString *s)
}
}
-/*
- * call-seq:
- * char* str = String("abcd"), len=strlen("abcd")
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
-const char*
-mrb_str_body(mrb_value str, int *len_p)
+static mrb_value
+byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ struct RString *orig, *s;
+ mrb_shared_string *shared;
+
+ orig = mrb_str_ptr(str);
+ if (RSTR_EMBED_P(orig)) {
+ s = str_new(mrb, orig->as.ary+beg, len);
+ }
+ else {
+ str_make_shared(mrb, orig);
+ shared = orig->as.heap.aux.shared;
+ s = mrb_obj_alloc_string(mrb);
+ s->as.heap.ptr = orig->as.heap.ptr + beg;
+ s->as.heap.len = len;
+ s->as.heap.aux.shared = shared;
+ RSTR_SET_SHARED_FLAG(s);
+ shared->refcnt++;
+ }
+
+ return mrb_obj_value(s);
+}
+#ifdef MRB_UTF8_STRING
+static inline mrb_value
+str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ beg = chars2bytes(str, 0, beg);
+ len = chars2bytes(str, beg, len);
+
+ return byte_subseq(mrb, str, beg, len);
+}
+#else
+#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len)
+#endif
+
+static mrb_value
+str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
+{
+ mrb_int clen = RSTRING_CHAR_LEN(str);
+
+ if (len < 0) return mrb_nil_value();
+ if (clen == 0) {
+ len = 0;
+ }
+ else if (beg < 0) {
+ beg = clen + beg;
+ }
+ if (beg > clen) return mrb_nil_value();
+ if (beg < 0) {
+ beg += clen;
+ if (beg < 0) return mrb_nil_value();
+ }
+ if (beg + len > clen)
+ len = clen - beg;
+ if (len <= 0) {
+ len = 0;
+ }
+ return str_subseq(mrb, str, beg, len);
+}
+
+static mrb_int
+str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
+{
+ mrb_int pos;
+ char *s, *sptr;
+ mrb_int len, slen;
+
+ len = RSTRING_LEN(str);
+ slen = RSTRING_LEN(sub);
+ if (offset < 0) {
+ offset += len;
+ if (offset < 0) return -1;
+ }
+ if (len - offset < slen) return -1;
+ s = RSTRING_PTR(str);
+ if (offset) {
+ s += offset;
+ }
+ if (slen == 0) return offset;
+ /* need proceed one character at a time */
+ sptr = RSTRING_PTR(sub);
+ slen = RSTRING_LEN(sub);
+ len = RSTRING_LEN(str) - offset;
+ pos = mrb_memsearch(sptr, slen, s, len);
+ if (pos < 0) return pos;
+ return pos + offset;
+}
+
+static void
+check_frozen(mrb_state *mrb, struct RString *s)
+{
+ if (RSTR_FROZEN_P(s)) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
+ }
+}
+
+static mrb_value
+str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
+{
+ long len;
+
+ check_frozen(mrb, s1);
+ len = RSTR_LEN(s2);
+ if (RSTR_SHARED_P(s1)) {
+ str_decref(mrb, s1->as.heap.aux.shared);
+ }
+ else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) {
+ mrb_free(mrb, s1->as.heap.ptr);
+ }
+
+ RSTR_UNSET_NOFREE_FLAG(s1);
+
+ if (RSTR_SHARED_P(s2)) {
+L_SHARE:
+ RSTR_UNSET_EMBED_FLAG(s1);
+ s1->as.heap.ptr = s2->as.heap.ptr;
+ s1->as.heap.len = len;
+ s1->as.heap.aux.shared = s2->as.heap.aux.shared;
+ RSTR_SET_SHARED_FLAG(s1);
+ s1->as.heap.aux.shared->refcnt++;
+ }
+ else {
+ if (len <= RSTRING_EMBED_LEN_MAX) {
+ RSTR_UNSET_SHARED_FLAG(s1);
+ RSTR_SET_EMBED_FLAG(s1);
+ memcpy(s1->as.ary, RSTR_PTR(s2), len);
+ RSTR_SET_EMBED_LEN(s1, len);
+ }
+ else {
+ str_make_shared(mrb, s2);
+ goto L_SHARE;
+ }
+ }
+
+ return mrb_obj_value(s1);
+}
+
+static mrb_int
+str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
+{
+ char *s, *sbeg, *t;
+ struct RString *ps = mrb_str_ptr(str);
+ mrb_int len = RSTRING_LEN(sub);
+
+ /* substring longer than string */
+ if (RSTR_LEN(ps) < len) return -1;
+ if (RSTR_LEN(ps) - pos < len) {
+ pos = RSTR_LEN(ps) - len;
+ }
+ sbeg = RSTR_PTR(ps);
+ s = RSTR_PTR(ps) + pos;
+ t = RSTRING_PTR(sub);
+ if (len) {
+ while (sbeg <= s) {
+ if (memcmp(s, t, len) == 0) {
+ return s - RSTR_PTR(ps);
+ }
+ s--;
+ }
+ return -1;
+ }
+ else {
+ return pos;
+ }
+}
+
+MRB_API mrb_int
+mrb_str_strlen(mrb_state *mrb, struct RString *s)
+{
+ mrb_int i, max = RSTR_LEN(s);
+ char *p = RSTR_PTR(s);
+
+ if (!p) return 0;
+ for (i=0; i<max; i++) {
+ if (p[i] == '\0') {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ }
+ }
+ return max;
+}
+
+#ifdef _WIN32
+#include <windows.h>
+
+char*
+mrb_utf8_from_locale(const char *str, size_t len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ size_t mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = strlen(str);
+ wcssize = MultiByteToWideChar(GetACP(), 0, str, len, NULL, 0);
+ wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t));
+ if (!wcsp)
+ return NULL;
+ wcssize = MultiByteToWideChar(GetACP(), 0, str, len, wcsp, wcssize + 1);
+ wcsp[wcssize] = 0;
+
+ mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL);
+ mbsp = (char*) malloc((mbssize + 1));
+ if (!mbsp) {
+ free(wcsp);
+ return NULL;
+ }
+ mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL);
+ mbsp[mbssize] = 0;
+ free(wcsp);
+ return mbsp;
+}
+
+char*
+mrb_locale_from_utf8(const char *utf8, size_t len)
+{
+ wchar_t* wcsp;
+ char* mbsp;
+ size_t mbssize, wcssize;
+
+ if (len == 0)
+ return strdup("");
+ if (len == -1)
+ len = strlen(utf8);
+ wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
+ wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t));
+ if (!wcsp)
+ return NULL;
+ wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wcsp, wcssize + 1);
+ wcsp[wcssize] = 0;
+ mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL);
+ mbsp = (char*) malloc((mbssize + 1));
+ if (!mbsp) {
+ free(wcsp);
+ return NULL;
+ }
+ mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL);
+ mbsp[mbssize] = 0;
+ free(wcsp);
+ return mbsp;
+}
+#endif
+
+MRB_API void
+mrb_str_modify(mrb_state *mrb, struct RString *s)
+{
+ check_frozen(mrb, s);
+ if (RSTR_SHARED_P(s)) {
+ mrb_shared_string *shared = s->as.heap.aux.shared;
+
+ if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
+ s->as.heap.ptr = shared->ptr;
+ s->as.heap.aux.capa = shared->len;
+ RSTR_PTR(s)[s->as.heap.len] = '\0';
+ mrb_free(mrb, shared);
+ }
+ else {
+ char *ptr, *p;
+ mrb_int len;
+
+ p = RSTR_PTR(s);
+ len = s->as.heap.len;
+ ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
+ if (p) {
+ memcpy(ptr, p, len);
+ }
+ ptr[len] = '\0';
+ s->as.heap.ptr = ptr;
+ s->as.heap.aux.capa = len;
+ str_decref(mrb, shared);
+ }
+ RSTR_UNSET_SHARED_FLAG(s);
+ return;
+ }
+ if (RSTR_NOFREE_P(s)) {
+ char *p = s->as.heap.ptr;
+
+ s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
+ if (p) {
+ memcpy(RSTR_PTR(s), p, s->as.heap.len);
+ }
+ RSTR_PTR(s)[s->as.heap.len] = '\0';
+ s->as.heap.aux.capa = s->as.heap.len;
+ RSTR_UNSET_NOFREE_FLAG(s);
+ return;
+ }
+}
+
+static mrb_value
+mrb_str_freeze(mrb_state *mrb, mrb_value str)
+{
+ struct RString *s = mrb_str_ptr(str);
+
+ RSTR_SET_FROZEN_FLAG(s);
+ return str;
+}
+
+MRB_API mrb_value
+mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
{
+ mrb_int slen;
struct RString *s = mrb_str_ptr(str);
- *len_p = RSTR_LEN(s);
+ mrb_str_modify(mrb, s);
+ slen = RSTR_LEN(s);
+ if (len != slen) {
+ if (slen < len || slen - len > 256) {
+ resize_capa(mrb, s, len);
+ }
+ RSTR_SET_LEN(s, len);
+ RSTR_PTR(s)[len] = '\0'; /* sentinel */
+ }
+ return str;
+}
+
+MRB_API char*
+mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
+{
+ struct RString *s;
+
+ if (!mrb_string_p(str0)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "expected String");
+ }
+
+ s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
+ if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ }
return RSTR_PTR(s);
}
@@ -381,7 +739,7 @@ mrb_str_body(mrb_value str, int *len_p)
*
* Returns a new string object containing a copy of <i>str</i>.
*/
-void
+MRB_API void
mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
struct RString *s1 = mrb_str_ptr(self), *s2;
@@ -408,7 +766,7 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
*
* Returns a new string object containing a copy of <i>str</i>.
*/
-mrb_value
+MRB_API mrb_value
mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
{
struct RString *s = mrb_str_ptr(a);
@@ -439,32 +797,26 @@ mrb_str_plus_m(mrb_state *mrb, mrb_value self)
return mrb_str_plus(mrb, self, str);
}
+/* 15.2.10.5.26 */
+/* 15.2.10.5.33 */
/*
* call-seq:
- * len = strlen(String("abcd"))
+ * "abcd".size => int
*
- * Returns a new string object containing a copy of <i>str</i>.
+ * Returns the length of string.
*/
static mrb_value
-mrb_str_bytesize(mrb_state *mrb, mrb_value self)
+mrb_str_size(mrb_state *mrb, mrb_value self)
{
- struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(RSTR_LEN(s));
+ mrb_int len = RSTRING_CHAR_LEN(self);
+ return mrb_fixnum_value(len);
}
-/* 15.2.10.5.26 */
-/* 15.2.10.5.33 */
-/*
- * call-seq:
- * len = strlen(String("abcd"))
- *
- * Returns a new string object containing a copy of <i>str</i>.
- */
-mrb_value
-mrb_str_size(mrb_state *mrb, mrb_value self)
+static mrb_value
+mrb_str_bytesize(mrb_state *mrb, mrb_value self)
{
- struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(RSTR_LEN(s));
+ mrb_int len = RSTRING_LEN(self);
+ return mrb_fixnum_value(len);
}
/* 15.2.10.5.1 */
@@ -521,7 +873,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
* = 0
* < -1
*/
-int
+MRB_API int
mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
{
mrb_int len;
@@ -607,7 +959,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2)
return FALSE;
}
-mrb_bool
+MRB_API mrb_bool
mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2)
{
if (mrb_immediate_p(str2)) return FALSE;
@@ -643,7 +995,7 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1)
return mrb_bool_value(mrb_str_equal(mrb, str1, str2));
}
/* ---------------------------------- */
-mrb_value
+MRB_API mrb_value
mrb_str_to_str(mrb_state *mrb, mrb_value str)
{
mrb_value s;
@@ -658,100 +1010,35 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str)
return str;
}
-char *
+MRB_API const char*
mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr)
{
mrb_value str = mrb_str_to_str(mrb, ptr);
return RSTRING_PTR(str);
}
-static mrb_value
-noregexp(mrb_state *mrb, mrb_value self)
-{
- mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented");
- return mrb_nil_value();
-}
-
-static void
-regexp_check(mrb_state *mrb, mrb_value obj)
+MRB_API mrb_int
+mrb_string_value_len(mrb_state *mrb, mrb_value ptr)
{
- if (mrb_regexp_p(mrb, obj)) {
- noregexp(mrb, obj);
- }
-}
-
-static inline mrb_int
-mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n)
-{
- const unsigned char *x = xs, *xe = xs + m;
- const unsigned char *y = ys;
- int i, qstable[256];
-
- /* Preprocessing */
- for (i = 0; i < 256; ++i)
- qstable[i] = m + 1;
- for (; x < xe; ++x)
- qstable[*x] = xe - x;
- /* Searching */
- for (; y + m <= ys + n; y += *(qstable + y[m])) {
- if (*xs == *y && memcmp(xs, y, m) == 0)
- return y - ys;
- }
- return -1;
+ mrb_value str = mrb_str_to_str(mrb, ptr);
+ return RSTRING_LEN(str);
}
-static mrb_int
-mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
+void
+mrb_noregexp(mrb_state *mrb, mrb_value self)
{
- const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0;
-
- if (m > n) return -1;
- else if (m == n) {
- return memcmp(x0, y0, m) == 0 ? 0 : -1;
- }
- else if (m < 1) {
- return 0;
- }
- else if (m == 1) {
- const unsigned char *ys = y, *ye = ys + n;
- for (; y < ye; ++y) {
- if (*x == *y)
- return y - ys;
- }
- return -1;
- }
- return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
+ mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented");
}
-static mrb_int
-mrb_str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
+void
+mrb_regexp_check(mrb_state *mrb, mrb_value obj)
{
- mrb_int pos;
- char *s, *sptr;
- mrb_int len, slen;
-
- len = RSTRING_LEN(str);
- slen = RSTRING_LEN(sub);
- if (offset < 0) {
- offset += len;
- if (offset < 0) return -1;
- }
- if (len - offset < slen) return -1;
- s = RSTRING_PTR(str);
- if (offset) {
- s += offset;
+ if (mrb_regexp_p(mrb, obj)) {
+ mrb_noregexp(mrb, obj);
}
- if (slen == 0) return offset;
- /* need proceed one character at a time */
- sptr = RSTRING_PTR(sub);
- slen = RSTRING_LEN(sub);
- len = RSTRING_LEN(str) - offset;
- pos = mrb_memsearch(sptr, slen, s, len);
- if (pos < 0) return pos;
- return pos + offset;
}
-mrb_value
+MRB_API mrb_value
mrb_str_dup(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
@@ -766,18 +1053,18 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx)
{
mrb_int idx;
- regexp_check(mrb, indx);
+ mrb_regexp_check(mrb, indx);
switch (mrb_type(indx)) {
case MRB_TT_FIXNUM:
idx = mrb_fixnum(indx);
num_index:
- str = mrb_str_substr(mrb, str, idx, 1);
+ str = str_substr(mrb, str, idx, 1);
if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value();
return str;
case MRB_TT_STRING:
- if (mrb_str_index(mrb, str, indx, 0) != -1)
+ if (str_index(mrb, str, indx, 0) != -1)
return mrb_str_dup(mrb, indx);
return mrb_nil_value();
@@ -786,15 +1073,20 @@ num_index:
{
mrb_int beg, len;
- len = RSTRING_LEN(str);
+ len = RSTRING_CHAR_LEN(str);
if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
- return mrb_str_subseq(mrb, str, beg, len);
+ return str_subseq(mrb, str, beg, len);
}
else {
return mrb_nil_value();
}
}
+ case MRB_TT_FLOAT:
default:
+ indx = mrb_Integer(mrb, indx);
+ if (mrb_nil_p(indx)) {
+ mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum");
+ }
idx = mrb_fixnum(indx);
goto num_index;
}
@@ -831,6 +1123,7 @@ num_index:
*
* a = "hello there"
* a[1] #=> 101(1.8.7) "e"(1.9.2)
+ * a[1.1] #=> "e"(1.9.2)
* a[1,3] #=> "ell"
* a[1..3] #=> "ell"
* a[-3,2] #=> "er"
@@ -848,8 +1141,8 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str)
argc = mrb_get_args(mrb, "o|o", &a1, &a2);
if (argc == 2) {
- regexp_check(mrb, a1);
- return mrb_str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2));
+ mrb_regexp_check(mrb, a1);
+ return str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2));
}
if (argc != 1) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
@@ -919,7 +1212,7 @@ mrb_str_capitalize(mrb_state *mrb, mrb_value self)
/* 15.2.10.5.10 */
/*
* call-seq:
- * str.chomp!(separator=$/) => str or nil
+ * str.chomp!(separator="\n") => str or nil
*
* Modifies <i>str</i> in place as described for <code>String#chomp</code>,
* returning <i>str</i>, or <code>nil</code> if no modifications were made.
@@ -993,7 +1286,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
/* 15.2.10.5.9 */
/*
* call-seq:
- * str.chomp(separator=$/) => new_str
+ * str.chomp(separator="\n") => new_str
*
* Returns a new <code>String</code> with the given record separator removed
* from the end of <i>str</i> (if present). If <code>$/</code> has not been
@@ -1036,7 +1329,18 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
mrb_str_modify(mrb, s);
if (RSTR_LEN(s) > 0) {
mrb_int len;
+#ifdef MRB_UTF8_STRING
+ const char* t = RSTR_PTR(s), *p = t;
+ const char* e = p + RSTR_LEN(s);
+ while (p<e) {
+ mrb_int clen = utf8len(p, e);
+ if (p + clen>=e) break;
+ p += clen;
+ }
+ len = p - t;
+#else
len = RSTR_LEN(s) - 1;
+#endif
if (RSTR_PTR(s)[len] == '\n') {
if (len > 0 &&
RSTR_PTR(s)[len-1] == '\r') {
@@ -1113,7 +1417,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
*
* Returns a copy of <i>str</i> with all uppercase letters replaced with their
* lowercase counterparts. The operation is locale insensitive---only
- * characters ``A'' to ``Z'' are affected.
+ * characters 'A' to 'Z' are affected.
*
* "hEllO".downcase #=> "hello"
*/
@@ -1164,47 +1468,10 @@ mrb_str_eql(mrb_state *mrb, mrb_value self)
return mrb_bool_value(eql_p);
}
-static mrb_value
-mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
-{
- struct RString *orig, *s;
- mrb_shared_string *shared;
-
- orig = mrb_str_ptr(str);
- if (RSTR_EMBED_P(orig)) {
- s = str_new(mrb, orig->as.ary+beg, len);
- } else {
- str_make_shared(mrb, orig);
- shared = orig->as.heap.aux.shared;
- s = mrb_obj_alloc_string(mrb);
- s->as.heap.ptr = orig->as.heap.ptr + beg;
- s->as.heap.len = len;
- s->as.heap.aux.shared = shared;
- RSTR_SET_SHARED_FLAG(s);
- shared->refcnt++;
- }
-
- return mrb_obj_value(s);
-}
-
-mrb_value
+MRB_API mrb_value
mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
{
- if (len < 0) return mrb_nil_value();
- if (!RSTRING_LEN(str)) {
- len = 0;
- }
- if (beg > RSTRING_LEN(str)) return mrb_nil_value();
- if (beg < 0) {
- beg += RSTRING_LEN(str);
- if (beg < 0) return mrb_nil_value();
- }
- if (beg + len > RSTRING_LEN(str))
- len = RSTRING_LEN(str) - beg;
- if (len <= 0) {
- len = 0;
- }
- return mrb_str_subseq(mrb, str, beg, len);
+ return str_substr(mrb, str, beg, len);
}
mrb_int
@@ -1263,7 +1530,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
}
else {
str2 = mrb_str_to_str(mrb, str2);
- i = mrb_str_index(mrb, self, str2, 0);
+ i = str_index(mrb, self, str2, 0);
include_p = (i != -1);
}
@@ -1293,12 +1560,12 @@ mrb_str_include(mrb_state *mrb, mrb_value self)
* "hello".index(/[aeiou]/, -3) #=> 4
*/
static mrb_value
-mrb_str_index_m(mrb_state *mrb, mrb_value str)
+mrb_str_index(mrb_state *mrb, mrb_value str)
{
mrb_value *argv;
mrb_int argc;
mrb_value sub;
- mrb_int pos;
+ mrb_int pos, clen;
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 2) {
@@ -1312,26 +1579,18 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
else
sub = mrb_nil_value();
}
- regexp_check(mrb, sub);
+ mrb_regexp_check(mrb, sub);
+ clen = RSTRING_CHAR_LEN(str);
if (pos < 0) {
- pos += RSTRING_LEN(str);
+ pos += clen;
if (pos < 0) {
return mrb_nil_value();
}
}
+ if (pos >= clen) return mrb_nil_value();
+ pos = chars2bytes(str, 0, pos);
switch (mrb_type(sub)) {
- case MRB_TT_FIXNUM: {
- int c = mrb_fixnum(sub);
- mrb_int len = RSTRING_LEN(str);
- unsigned char *p = (unsigned char*)RSTRING_PTR(str);
-
- for (;pos<len;pos++) {
- if (p[pos] == c) return mrb_fixnum_value(pos);
- }
- return mrb_nil_value();
- }
-
default: {
mrb_value tmp;
@@ -1343,56 +1602,17 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str)
}
/* fall through */
case MRB_TT_STRING:
- pos = mrb_str_index(mrb, str, sub, pos);
+ pos = str_index(mrb, str, sub, pos);
break;
}
if (pos == -1) return mrb_nil_value();
+ pos = bytes2chars(RSTRING_PTR(str), pos);
return mrb_fixnum_value(pos);
}
#define STR_REPLACE_SHARED_MIN 10
-static mrb_value
-str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
-{
- long len;
-
- len = RSTR_LEN(s2);
- if (RSTR_SHARED_P(s1)) {
- str_decref(mrb, s1->as.heap.aux.shared);
- }
- else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) {
- mrb_free(mrb, s1->as.heap.ptr);
- }
-
- RSTR_UNSET_NOFREE_FLAG(s1);
-
- if (RSTR_SHARED_P(s2)) {
-L_SHARE:
- RSTR_UNSET_EMBED_FLAG(s1);
- s1->as.heap.ptr = s2->as.heap.ptr;
- s1->as.heap.len = len;
- s1->as.heap.aux.shared = s2->as.heap.aux.shared;
- RSTR_SET_SHARED_FLAG(s1);
- s1->as.heap.aux.shared->refcnt++;
- }
- else {
- if (len <= RSTRING_EMBED_LEN_MAX) {
- RSTR_UNSET_SHARED_FLAG(s1);
- RSTR_SET_EMBED_FLAG(s1);
- memcpy(s1->as.ary, RSTR_PTR(s2), len);
- RSTR_SET_EMBED_LEN(s1, len);
- }
- else {
- str_make_shared(mrb, s2);
- goto L_SHARE;
- }
- }
-
- return mrb_obj_value(s1);
-}
-
/* 15.2.10.5.24 */
/* 15.2.10.5.28 */
/*
@@ -1450,13 +1670,13 @@ mrb_str_init(mrb_state *mrb, mrb_value self)
*
* 'cat and dog'.to_sym #=> :"cat and dog"
*/
-mrb_value
+MRB_API mrb_value
mrb_str_intern(mrb_state *mrb, mrb_value self)
{
return mrb_symbol_value(mrb_intern_str(mrb, self));
}
/* ---------------------------------- */
-mrb_value
+MRB_API mrb_value
mrb_obj_as_string(mrb_state *mrb, mrb_value obj)
{
mrb_value str;
@@ -1470,7 +1690,7 @@ mrb_obj_as_string(mrb_state *mrb, mrb_value obj)
return str;
}
-mrb_value
+MRB_API mrb_value
mrb_ptr_to_str(mrb_state *mrb, void *p)
{
struct RString *p_str;
@@ -1500,119 +1720,93 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
return mrb_obj_value(p_str);
}
-mrb_value
+MRB_API mrb_value
mrb_string_type(mrb_state *mrb, mrb_value str)
{
return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str");
}
-mrb_value
+MRB_API mrb_value
mrb_check_string_type(mrb_state *mrb, mrb_value str)
{
return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str");
}
-/* ---------------------------------- */
-/* 15.2.10.5.29 */
+/* 15.2.10.5.30 */
/*
* call-seq:
- * str.reverse => new_str
- *
- * Returns a new string with the characters from <i>str</i> in reverse order.
+ * str.reverse! => str
*
- * "stressed".reverse #=> "desserts"
+ * Reverses <i>str</i> in place.
*/
static mrb_value
-mrb_str_reverse(mrb_state *mrb, mrb_value str)
+mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
{
- struct RString *s2;
- char *s, *e, *p;
+#ifdef MRB_UTF8_STRING
+ mrb_int utf8_len = RSTRING_CHAR_LEN(str);
+ mrb_int len = RSTRING_LEN(str);
+
+ if (utf8_len == len) goto bytes;
+ if (utf8_len > 1) {
+ char *buf;
+ char *p, *e, *r;
- if (RSTRING_LEN(str) <= 1) return mrb_str_dup(mrb, str);
+ mrb_str_modify(mrb, mrb_str_ptr(str));
+ len = RSTRING_LEN(str);
+ buf = mrb_malloc(mrb, (size_t)len);
+ p = buf;
+ e = buf + len;
- s2 = str_new(mrb, 0, RSTRING_LEN(str));
- str_with_class(mrb, s2, str);
- s = RSTRING_PTR(str); e = RSTRING_END(str) - 1;
- p = RSTR_PTR(s2);
+ memcpy(buf, RSTRING_PTR(str), len);
+ r = RSTRING_PTR(str) + len;
- while (e >= s) {
- *p++ = *e--;
+ while (p<e) {
+ mrb_int clen = utf8len(p, e);
+ r -= clen;
+ memcpy(r, p, clen);
+ p += clen;
+ }
+ mrb_free(mrb, buf);
}
- return mrb_obj_value(s2);
-}
+ return str;
-/* 15.2.10.5.30 */
-/*
- * call-seq:
- * str.reverse! => str
- *
- * Reverses <i>str</i> in place.
- */
-static mrb_value
-mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
-{
- struct RString *s = mrb_str_ptr(str);
- char *p, *e;
- char c;
+ bytes:
+#endif
+ {
+ struct RString *s = mrb_str_ptr(str);
+ char *p, *e;
+ char c;
- mrb_str_modify(mrb, s);
- if (RSTR_LEN(s) > 1) {
- p = RSTR_PTR(s);
- e = p + RSTR_LEN(s) - 1;
- while (p < e) {
+ mrb_str_modify(mrb, s);
+ if (RSTR_LEN(s) > 1) {
+ p = RSTR_PTR(s);
+ e = p + RSTR_LEN(s) - 1;
+ while (p < e) {
c = *p;
*p++ = *e;
*e-- = c;
+ }
}
+ return str;
}
- return str;
}
+/* ---------------------------------- */
+/* 15.2.10.5.29 */
/*
* call-seq:
- * str.rindex(substring [, fixnum]) => fixnum or nil
- * str.rindex(fixnum [, fixnum]) => fixnum or nil
- * str.rindex(regexp [, fixnum]) => fixnum or nil
+ * str.reverse => new_str
*
- * Returns the index of the last occurrence of the given <i>substring</i>,
- * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns
- * <code>nil</code> if not found. If the second parameter is present, it
- * specifies the position in the string to end the search---characters beyond
- * this point will not be considered.
+ * Returns a new string with the characters from <i>str</i> in reverse order.
*
- * "hello".rindex('e') #=> 1
- * "hello".rindex('l') #=> 3
- * "hello".rindex('a') #=> nil
- * "hello".rindex(101) #=> 1
- * "hello".rindex(/[aeiou]/, -2) #=> 1
+ * "stressed".reverse #=> "desserts"
*/
-static mrb_int
-mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
+static mrb_value
+mrb_str_reverse(mrb_state *mrb, mrb_value str)
{
- char *s, *sbeg, *t;
- struct RString *ps = mrb_str_ptr(str);
- mrb_int len = RSTRING_LEN(sub);
-
- /* substring longer than string */
- if (RSTR_LEN(ps) < len) return -1;
- if (RSTR_LEN(ps) - pos < len) {
- pos = RSTR_LEN(ps) - len;
- }
- sbeg = RSTR_PTR(ps);
- s = RSTR_PTR(ps) + pos;
- t = RSTRING_PTR(sub);
- if (len) {
- while (sbeg <= s) {
- if (memcmp(s, t, len) == 0) {
- return s - RSTR_PTR(ps);
- }
- s--;
- }
- return -1;
- }
- else {
- return pos;
- }
+ mrb_value str2 = mrb_str_dup(mrb, str);
+ mrb_str_reverse_bang(mrb, str2);
+ return str2;
}
/* 15.2.10.5.31 */
@@ -1635,13 +1829,13 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
* "hello".rindex(/[aeiou]/, -2) #=> 1
*/
static mrb_value
-mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
+mrb_str_rindex(mrb_state *mrb, mrb_value str)
{
mrb_value *argv;
mrb_int argc;
mrb_value sub;
mrb_value vpos;
- mrb_int pos, len = RSTRING_LEN(str);
+ mrb_int pos, len = RSTRING_CHAR_LEN(str);
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 2) {
@@ -1651,7 +1845,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
if (pos < 0) {
pos += len;
if (pos < 0) {
- regexp_check(mrb, sub);
+ mrb_regexp_check(mrb, sub);
return mrb_nil_value();
}
}
@@ -1664,20 +1858,11 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
else
sub = mrb_nil_value();
}
- regexp_check(mrb, sub);
+ pos = chars2bytes(str, 0, pos);
+ len = chars2bytes(str, pos, len);
+ mrb_regexp_check(mrb, sub);
switch (mrb_type(sub)) {
- case MRB_TT_FIXNUM: {
- int c = mrb_fixnum(sub);
- mrb_int len = RSTRING_LEN(str);
- unsigned char *p = (unsigned char*)RSTRING_PTR(str);
-
- for (pos=len-1;pos>=0;pos--) {
- if (p[pos] == c) return mrb_fixnum_value(pos);
- }
- return mrb_nil_value();
- }
-
default: {
mrb_value tmp;
@@ -1689,8 +1874,11 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
}
/* fall through */
case MRB_TT_STRING:
- pos = mrb_str_rindex(mrb, str, sub, pos);
- if (pos >= 0) return mrb_fixnum_value(pos);
+ pos = str_rindex(mrb, str, sub, pos);
+ if (pos >= 0) {
+ pos = bytes2chars(RSTRING_PTR(str), pos);
+ return mrb_fixnum_value(pos);
+ }
break;
} /* end of switch (TYPE(sub)) */
@@ -1701,7 +1889,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
/*
* call-seq:
- * str.split(pattern=$;, [limit]) => anArray
+ * str.split(pattern="\n", [limit]) => anArray
*
* Divides <i>str</i> into substrings based on a delimiter, returning an array
* of these substrings.
@@ -1717,7 +1905,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
*
* If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If
* <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is
- * split on whitespace as if ` ' were specified.
+ * split on whitespace as if ' ' were specified.
*
* If the <i>limit</i> parameter is omitted, trailing null fields are
* suppressed. If <i>limit</i> is a positive number, at most that number of
@@ -1729,10 +1917,8 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
* " now's the time".split #=> ["now's", "the", "time"]
* " now's the time".split(' ') #=> ["now's", "the", "time"]
* " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"]
- * "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"]
* "hello".split(//) #=> ["h", "e", "l", "l", "o"]
* "hello".split(//, 3) #=> ["h", "e", "llo"]
- * "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"]
*
* "mellow yellow".split("ello") #=> ["m", "w y", "w"]
* "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"]
@@ -1774,83 +1960,73 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
}
else {
- noregexp(mrb, str);
+ mrb_noregexp(mrb, str);
}
}
result = mrb_ary_new(mrb);
beg = 0;
if (split_type == awk) {
- char *ptr = RSTRING_PTR(str);
- char *eptr = RSTRING_END(str);
- char *bptr = ptr;
mrb_bool skip = TRUE;
+ mrb_int idx = 0;
+ mrb_int str_len = RSTRING_LEN(str);
unsigned int c;
+ int ai = mrb_gc_arena_save(mrb);
- end = beg;
- while (ptr < eptr) {
- int ai = mrb_gc_arena_save(mrb);
- c = (unsigned char)*ptr++;
+ idx = end = beg;
+ while (idx < str_len) {
+ c = (unsigned char)RSTRING_PTR(str)[idx++];
if (skip) {
if (ISSPACE(c)) {
- beg = ptr - bptr;
+ beg = idx;
}
else {
- end = ptr - bptr;
+ end = idx;
skip = FALSE;
if (lim_p && lim <= i) break;
}
}
else if (ISSPACE(c)) {
- mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, beg, end-beg));
+ mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg));
mrb_gc_arena_restore(mrb, ai);
skip = TRUE;
- beg = ptr - bptr;
+ beg = idx;
if (lim_p) ++i;
}
else {
- end = ptr - bptr;
+ end = idx;
}
}
}
else if (split_type == string) {
- char *ptr = RSTRING_PTR(str); // s->as.ary
- char *temp = ptr;
- char *eptr = RSTRING_END(str);
- mrb_int slen = RSTRING_LEN(spat);
-
- if (slen == 0) {
- int ai = mrb_gc_arena_save(mrb);
- while (ptr < eptr) {
- mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr-temp, 1));
- mrb_gc_arena_restore(mrb, ai);
- ptr++;
- if (lim_p && lim <= ++i) break;
+ mrb_int str_len = RSTRING_LEN(str);
+ mrb_int pat_len = RSTRING_LEN(spat);
+ mrb_int idx = 0;
+ int ai = mrb_gc_arena_save(mrb);
+
+ while (idx < str_len) {
+ if (pat_len > 0) {
+ end = mrb_memsearch(RSTRING_PTR(spat), pat_len, RSTRING_PTR(str)+idx, str_len - idx);
+ if (end < 0) break;
+ } else {
+ end = chars2bytes(str, idx, 1);
}
+ mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end));
+ mrb_gc_arena_restore(mrb, ai);
+ idx += end + pat_len;
+ if (lim_p && lim <= ++i) break;
}
- else {
- char *sptr = RSTRING_PTR(spat);
- int ai = mrb_gc_arena_save(mrb);
-
- while (ptr < eptr &&
- (end = mrb_memsearch(sptr, slen, ptr, eptr - ptr)) >= 0) {
- mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr - temp, end));
- mrb_gc_arena_restore(mrb, ai);
- ptr += end + slen;
- if (lim_p && lim <= ++i) break;
- }
- }
- beg = ptr - temp;
+ beg = idx;
}
else {
- noregexp(mrb, str);
+ mrb_noregexp(mrb, str);
}
if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) {
if (RSTRING_LEN(str) == beg) {
tmp = mrb_str_new_empty(mrb, str);
}
else {
- tmp = mrb_str_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
+ tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg);
}
mrb_ary_push(mrb, result, tmp);
}
@@ -1864,44 +2040,39 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
-mrb_value
-mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
+MRB_API mrb_value
+mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, int base, int badcheck)
{
- const char *p;
+ const char *p = str;
+ const char *pend = str + len;
char sign = 1;
- int c, uscore;
- unsigned long n = 0;
+ int c;
+ uint64_t n = 0;
mrb_int val;
-#undef ISDIGIT
-#define ISDIGIT(c) ('0' <= (c) && (c) <= '9')
#define conv_digit(c) \
- (!ISASCII(c) ? -1 : \
- isdigit(c) ? ((c) - '0') : \
- islower(c) ? ((c) - 'a' + 10) : \
- isupper(c) ? ((c) - 'A' + 10) : \
+ (ISDIGIT(c) ? ((c) - '0') : \
+ ISLOWER(c) ? ((c) - 'a' + 10) : \
+ ISUPPER(c) ? ((c) - 'A' + 10) : \
-1)
- if (!str) {
+ if (!p) {
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
- while (ISSPACE(*str)) str++;
+ while (p<pend && ISSPACE(*p))
+ p++;
- if (str[0] == '+') {
- str++;
+ if (p[0] == '+') {
+ p++;
}
- else if (str[0] == '-') {
- str++;
+ else if (p[0] == '-') {
+ p++;
sign = 0;
}
- if (str[0] == '+' || str[0] == '-') {
- if (badcheck) goto bad;
- return mrb_fixnum_value(0);
- }
if (base <= 0) {
- if (str[0] == '0') {
- switch (str[1]) {
+ if (p[0] == '0') {
+ switch (p[1]) {
case 'x': case 'X':
base = 16;
break;
@@ -1916,6 +2087,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break;
default:
base = 8;
+ break;
}
}
else if (base < -1) {
@@ -1927,27 +2099,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
}
switch (base) {
case 2:
- if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) {
- str += 2;
+ if (p[0] == '0' && (p[1] == 'b'||p[1] == 'B')) {
+ p += 2;
}
break;
case 3:
break;
case 8:
- if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) {
- str += 2;
+ if (p[0] == '0' && (p[1] == 'o'||p[1] == 'O')) {
+ p += 2;
}
case 4: case 5: case 6: case 7:
break;
case 10:
- if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) {
- str += 2;
+ if (p[0] == '0' && (p[1] == 'd'||p[1] == 'D')) {
+ p += 2;
}
case 9: case 11: case 12: case 13: case 14: case 15:
break;
case 16:
- if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) {
- str += 2;
+ if (p[0] == '0' && (p[1] == 'x'||p[1] == 'X')) {
+ p += 2;
}
break;
default:
@@ -1956,96 +2128,109 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
}
break;
} /* end of switch (base) { */
- if (*str == '0') { /* squeeze preceeding 0s */
- uscore = 0;
- while ((c = *++str) == '0' || c == '_') {
+ if (p>=pend) {
+ if (badcheck) goto bad;
+ return mrb_fixnum_value(0);
+ }
+ if (*p == '0') { /* squeeze preceding 0s */
+ p++;
+ while (p<pend) {
+ c = *p++;
if (c == '_') {
- if (++uscore >= 2)
+ if (p<pend && *p == '_') {
+ if (badcheck) goto bad;
break;
+ }
+ continue;
+ }
+ if (c != '0') {
+ p--;
+ break;
}
- else
- uscore = 0;
}
- if (!(c = *str) || ISSPACE(c)) --str;
}
- c = *str;
- c = conv_digit(c);
- if (c < 0 || c >= base) {
+ if (p == pend) {
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
-
- uscore = 0;
- for (p=str;*p;p++) {
+ for ( ;p<pend;p++) {
if (*p == '_') {
- if (uscore == 0) {
- uscore++;
+ p++;
+ if (p==pend) {
+ if (badcheck) goto bad;
continue;
}
- if (badcheck) goto bad;
- break;
+ if (*p == '_') {
+ if (badcheck) goto bad;
+ break;
+ }
+ }
+ if (badcheck && *p == '\0') {
+ goto nullbyte;
}
- uscore = 0;
c = conv_digit(*p);
if (c < 0 || c >= base) {
- if (badcheck) goto bad;
break;
}
n *= base;
n += c;
+ if (n > (uint64_t)MRB_INT_MAX + (sign ? 0 : 1)) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer",
+ mrb_str_new(mrb, str, pend-str));
+ }
}
- if (n > MRB_INT_MAX) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str));
- }
- val = n;
+ val = (mrb_int)n;
if (badcheck) {
if (p == str) goto bad; /* no number */
- while (*p && ISSPACE(*p)) p++;
- if (*p) goto bad; /* trailing garbage */
+ while (p<pend && ISSPACE(*p)) p++;
+ if (p<pend) goto bad; /* trailing garbage */
}
return mrb_fixnum_value(sign ? val : -val);
-bad:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", mrb_str_new_cstr(mrb, str));
+ nullbyte:
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
+ /* not reached */
+ bad:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)",
+ mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str)));
/* not reached */
return mrb_fixnum_value(0);
}
-char *
+MRB_API mrb_value
+mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
+{
+ return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck);
+}
+
+MRB_API const char*
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
- struct RString *ps = mrb_str_ptr(*ptr);
+ mrb_value str = mrb_str_to_str(mrb, *ptr);
+ struct RString *ps = mrb_str_ptr(str);
mrb_int len = mrb_str_strlen(mrb, ps);
char *p = RSTR_PTR(ps);
if (!p || p[len] != '\0') {
+ if (RSTR_FROZEN_P(ps)) {
+ *ptr = str = mrb_str_dup(mrb, str);
+ ps = mrb_str_ptr(str);
+ }
mrb_str_modify(mrb, ps);
return RSTR_PTR(ps);
}
return p;
}
-mrb_value
+MRB_API mrb_value
mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
{
- char *s;
+ const char *s;
mrb_int len;
- str = mrb_str_to_str(mrb, str);
- if (badcheck) {
- s = mrb_string_value_cstr(mrb, &str);
- }
- else {
- s = RSTRING_PTR(str);
- }
- if (s) {
- len = RSTRING_LEN(str);
- if (s[len]) { /* no sentinel somehow */
- struct RString *temp_str = str_new(mrb, s, len);
- s = RSTR_PTR(temp_str);
- }
- }
- return mrb_cstr_to_inum(mrb, s, base, badcheck);
+ s = mrb_string_value_ptr(mrb, str);
+ len = RSTRING_LEN(str);
+ return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
}
/* 15.2.10.5.38 */
@@ -2081,16 +2266,14 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self)
return mrb_str_to_inum(mrb, self, base, FALSE);
}
-double
+MRB_API double
mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
{
char *end;
+ char buf[DBL_DIG * 4 + 10];
double d;
enum {max_width = 20};
-#define OutOfRange() (((w = end - p) > max_width) ? \
- (w = max_width, ellipsis = "...") : \
- (w = (int)(end - p), ellipsis = ""))
if (!p) return 0.0;
while (ISSPACE(*p)) p++;
@@ -2108,7 +2291,6 @@ bad:
return d;
}
if (*end) {
- char buf[DBL_DIG * 4 + 10];
char *n = buf;
char *e = buf + sizeof(buf) - 1;
char prev = 0;
@@ -2147,7 +2329,7 @@ bad:
return d;
}
-double
+MRB_API double
mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
{
char *s;
@@ -2242,7 +2424,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str)
*
* Returns a copy of <i>str</i> with all lowercase letters replaced with their
* uppercase counterparts. The operation is locale insensitive---only
- * characters ``a'' to ``z'' are affected.
+ * characters 'a' to 'z' are affected.
*
* "hEllO".upcase #=> "HELLO"
*/
@@ -2377,30 +2559,30 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
return mrb_obj_value(result);
}
-mrb_value
+MRB_API mrb_value
mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len)
{
str_buf_cat(mrb, mrb_str_ptr(str), ptr, len);
return str;
}
-mrb_value
+MRB_API mrb_value
mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr)
{
return mrb_str_cat(mrb, str, ptr, strlen(ptr));
}
-mrb_value
+MRB_API mrb_value
mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2)
{
return mrb_str_cat(mrb, str, RSTRING_PTR(str2), RSTRING_LEN(str2));
}
-mrb_value
-mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2)
+MRB_API mrb_value
+mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2)
{
str2 = mrb_str_to_str(mrb, str2);
- return mrb_str_cat_str(mrb, str, str2);
+ return mrb_str_cat_str(mrb, str1, str2);
}
#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
@@ -2426,7 +2608,21 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
p = RSTRING_PTR(str); pend = RSTRING_END(str);
for (;p < pend; p++) {
unsigned char c, cc;
+#ifdef MRB_UTF8_STRING
+ mrb_int clen;
+ clen = utf8len(p, pend);
+ if (clen > 1) {
+ mrb_int i;
+
+ for (i=0; i<clen; i++) {
+ buf[i] = p[i];
+ }
+ mrb_str_cat(mrb, result, buf, clen);
+ p += clen-1;
+ continue;
+ }
+#endif
c = *p;
if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) {
buf[0] = '\\'; buf[1] = c;
@@ -2500,7 +2696,7 @@ mrb_init_string(mrb_state *mrb)
mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string");
- s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
+ mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
mrb_define_method(mrb, s, "bytesize", mrb_str_bytesize, MRB_ARGS_NONE());
@@ -2511,7 +2707,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */
mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */
mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */
- mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.8 */
+ mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */
mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */
mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */
mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */
@@ -2521,9 +2717,9 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */
mrb_define_method(mrb, s, "eql?", mrb_str_eql, MRB_ARGS_REQ(1)); /* 15.2.10.5.17 */
- mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.20 */
+ mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */
mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */
- mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
+ mrb_define_method(mrb, s, "index", mrb_str_index, MRB_ARGS_ANY()); /* 15.2.10.5.22 */
mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */
mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */
mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */
@@ -2531,7 +2727,7 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "replace", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.28 */
mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); /* 15.2.10.5.29 */
mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); /* 15.2.10.5.30 */
- mrb_define_method(mrb, s, "rindex", mrb_str_rindex_m, MRB_ARGS_ANY()); /* 15.2.10.5.31 */
+ mrb_define_method(mrb, s, "rindex", mrb_str_rindex, MRB_ARGS_ANY()); /* 15.2.10.5.31 */
mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */
mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.34 */
mrb_define_method(mrb, s, "split", mrb_str_split_m, MRB_ARGS_ANY()); /* 15.2.10.5.35 */
@@ -2541,8 +2737,10 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */
mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */
- mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_REQ(1)); /* 15.2.10.5.42 */
- mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.43 */
+ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */
+ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */
mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE());
}
diff --git a/src/symbol.c b/src/symbol.c
index 148adc6fe..c39e88012 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -4,11 +4,12 @@
** See Copyright Notice in mruby.h
*/
-#include <ctype.h>
+#include <limits.h>
#include <string.h>
-#include "mruby.h"
-#include "mruby/khash.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/khash.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
/* ------------------------------------------------------ */
typedef struct symbol_name {
@@ -18,148 +19,153 @@ typedef struct symbol_name {
} symbol_name;
static inline khint_t
-sym_hash_func(mrb_state *mrb, const symbol_name s)
+sym_hash_func(mrb_state *mrb, mrb_sym s)
{
khint_t h = 0;
- size_t i;
- const char *p = s.name;
+ size_t i, len = mrb->symtbl[s].len;
+ const char *p = mrb->symtbl[s].name;
- for (i=0; i<s.len; i++) {
+ for (i=0; i<len; i++) {
h = (h << 5) - h + *p++;
}
return h;
}
-#define sym_hash_equal(mrb,a, b) (a.len == b.len && memcmp(a.name, b.name, a.len) == 0)
+#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0)
-KHASH_DECLARE(n2s, symbol_name, mrb_sym, TRUE)
-KHASH_DEFINE (n2s, symbol_name, mrb_sym, TRUE, sym_hash_func, sym_hash_equal)
+KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE)
+KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal)
/* ------------------------------------------------------ */
+
+static void
+sym_validate_len(mrb_state *mrb, size_t len)
+{
+ if (len >= RITE_LV_NULL_MARK) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ }
+}
+
static mrb_sym
sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
{
khash_t(n2s) *h = mrb->name2sym;
- symbol_name sname;
+ symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */
khiter_t k;
mrb_sym sym;
char *p;
- if (len > (UINT16_MAX-1)) { /* UINT16_MAX is reverved */
- mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
+ sym_validate_len(mrb, len);
+ if (sname) {
+ sname->lit = lit;
+ sname->len = (uint16_t)len;
+ sname->name = name;
+ k = kh_get(n2s, mrb, h, 0);
+ if (k != kh_end(h))
+ return kh_key(h, k);
}
- sname.lit = lit;
- sname.len = (uint16_t)len;
- sname.name = name;
- k = kh_get(n2s, mrb, h, sname);
- if (k != kh_end(h))
- return kh_value(h, k);
+ /* registering a new symbol */
sym = ++mrb->symidx;
- if (lit) {
- sname.name = name;
+ if (mrb->symcapa < sym) {
+ if (mrb->symcapa == 0) mrb->symcapa = 100;
+ else mrb->symcapa = (size_t)(mrb->symcapa * 1.2);
+ mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1));
+ }
+ sname = &mrb->symtbl[sym];
+ sname->len = (uint16_t)len;
+ if (lit || mrb_ro_data_p(name)) {
+ sname->name = name;
+ sname->lit = TRUE;
}
else {
p = (char *)mrb_malloc(mrb, len+1);
memcpy(p, name, len);
p[len] = 0;
- sname.name = (const char*)p;
+ sname->name = (const char*)p;
+ sname->lit = FALSE;
}
- k = kh_put(n2s, mrb, h, sname);
- kh_value(h, k) = sym;
+ kh_put(n2s, mrb, h, sym);
return sym;
}
-mrb_sym
+MRB_API mrb_sym
mrb_intern(mrb_state *mrb, const char *name, size_t len)
{
return sym_intern(mrb, name, len, FALSE);
}
-mrb_sym
+MRB_API mrb_sym
mrb_intern_static(mrb_state *mrb, const char *name, size_t len)
{
return sym_intern(mrb, name, len, TRUE);
}
-mrb_sym
+MRB_API mrb_sym
mrb_intern_cstr(mrb_state *mrb, const char *name)
{
return mrb_intern(mrb, name, strlen(name));
}
-mrb_sym
+MRB_API mrb_sym
mrb_intern_str(mrb_state *mrb, mrb_value str)
{
return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
-mrb_value
+MRB_API mrb_value
mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
{
khash_t(n2s) *h = mrb->name2sym;
- symbol_name sname = { 0 };
+ symbol_name *sname = mrb->symtbl;
khiter_t k;
- if (len > UINT16_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
- }
- sname.len = (uint16_t)len;
- sname.name = name;
+ sym_validate_len(mrb, len);
+ sname->len = (uint16_t)len;
+ sname->name = name;
- k = kh_get(n2s, mrb, h, sname);
+ k = kh_get(n2s, mrb, h, 0);
if (k != kh_end(h)) {
- return mrb_symbol_value(kh_value(h, k));
+ return mrb_symbol_value(kh_key(h, k));
}
return mrb_nil_value();
}
-mrb_value
+MRB_API mrb_value
mrb_check_intern_cstr(mrb_state *mrb, const char *name)
{
return mrb_check_intern(mrb, name, (mrb_int)strlen(name));
}
-mrb_value
+MRB_API mrb_value
mrb_check_intern_str(mrb_state *mrb, mrb_value str)
{
return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
}
/* lenp must be a pointer to a size_t variable */
-const char*
+MRB_API const char*
mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
{
- khash_t(n2s) *h = mrb->name2sym;
- khiter_t k;
- symbol_name sname;
-
- for (k = kh_begin(h); k != kh_end(h); k++) {
- if (kh_exist(h, k)) {
- if (kh_value(h, k) == sym) {
- sname = kh_key(h, k);
- if (lenp) *lenp = sname.len;
- return sname.name;
- }
- }
+ if (sym == 0 || mrb->symidx < sym) {
+ if (lenp) *lenp = 0;
+ return NULL;
}
- if (lenp) *lenp = 0;
- return NULL; /* missing */
+
+ if (lenp) *lenp = mrb->symtbl[sym].len;
+ return mrb->symtbl[sym].name;
}
void
mrb_free_symtbl(mrb_state *mrb)
{
- khash_t(n2s) *h = mrb->name2sym;
- khiter_t k;
-
- for (k = kh_begin(h); k != kh_end(h); k++)
- if (kh_exist(h, k)) {
- symbol_name s = kh_key(h, k);
+ mrb_sym i, lim;
- if (!s.lit) {
- mrb_free(mrb, (char*)s.name);
- }
+ for (i=1, lim=mrb->symidx+1; i<lim; i++) {
+ if (!mrb->symtbl[i].lit) {
+ mrb_free(mrb, (char*)mrb->symtbl[i].name);
}
+ }
+ mrb_free(mrb, mrb->symtbl);
kh_destroy(n2s, mrb, mrb->name2sym);
}
@@ -216,12 +222,10 @@ static mrb_value
sym_equal(mrb_state *mrb, mrb_value sym1)
{
mrb_value sym2;
- mrb_bool equal_p;
mrb_get_args(mrb, "o", &sym2);
- equal_p = mrb_obj_equal(mrb, sym1, sym2);
- return mrb_bool_value(equal_p);
+ return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2));
}
/* 15.2.11.3.2 */
@@ -235,7 +239,7 @@ sym_equal(mrb_state *mrb, mrb_value sym1)
*
* :fred.id2name #=> "fred"
*/
-mrb_value
+static mrb_value
mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
{
mrb_sym id = mrb_symbol(sym);
@@ -411,7 +415,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
return str;
}
-mrb_value
+MRB_API mrb_value
mrb_sym2str(mrb_state *mrb, mrb_sym sym)
{
mrb_int len;
@@ -421,7 +425,7 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym)
return mrb_str_new_static(mrb, name, len);
}
-const char*
+MRB_API const char*
mrb_sym2name(mrb_state *mrb, mrb_sym sym)
{
mrb_int len;
@@ -474,7 +478,7 @@ mrb_init_symbol(mrb_state *mrb)
{
struct RClass *sym;
- sym = mrb->symbol_class = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
+ mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */
mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
diff --git a/src/value_array.h b/src/value_array.h
index cabd2426d..bc5f28b06 100644
--- a/src/value_array.h
+++ b/src/value_array.h
@@ -1,7 +1,7 @@
#ifndef MRB_VALUE_ARRAY_H__
#define MRB_VALUE_ARRAY_H__
-#include "mruby.h"
+#include <mruby.h>
static inline void
value_move(mrb_value *s1, const mrb_value *s2, size_t n)
diff --git a/src/variable.c b/src/variable.c
index 74bb591cf..bda7b2a98 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -4,12 +4,11 @@
** See Copyright Notice in mruby.h
*/
-#include <ctype.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
@@ -283,7 +282,7 @@ iv_free(mrb_state *mrb, iv_tbl *t)
#else
-#include "mruby/khash.h"
+#include <mruby/khash.h>
#ifndef MRB_IVHASH_INIT_SIZE
#define MRB_IVHASH_INIT_SIZE 8
@@ -459,13 +458,14 @@ obj_iv_p(mrb_value obj)
case MRB_TT_SCLASS:
case MRB_TT_HASH:
case MRB_TT_DATA:
+ case MRB_TT_EXCEPTION:
return TRUE;
default:
return FALSE;
}
}
-mrb_value
+MRB_API mrb_value
mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
{
mrb_value v;
@@ -475,7 +475,7 @@ mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
return mrb_nil_value();
}
-mrb_value
+MRB_API mrb_value
mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
{
if (obj_iv_p(obj)) {
@@ -484,7 +484,7 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
return mrb_nil_value();
}
-void
+MRB_API void
mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t = obj->iv;
@@ -496,7 +496,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
iv_put(mrb, t, sym, v);
}
-void
+MRB_API void
mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
{
iv_tbl *t = obj->iv;
@@ -511,7 +511,7 @@ mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
iv_put(mrb, t, sym, v);
}
-void
+MRB_API void
mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
{
if (obj_iv_p(obj)) {
@@ -522,7 +522,7 @@ mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
}
}
-mrb_bool
+MRB_API mrb_bool
mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
{
iv_tbl *t;
@@ -534,14 +534,40 @@ mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
return FALSE;
}
-mrb_bool
+MRB_API mrb_bool
mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
{
if (!obj_iv_p(obj)) return FALSE;
return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
}
-void
+#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
+
+MRB_API mrb_bool
+mrb_iv_p(mrb_state *mrb, mrb_sym iv_name)
+{
+ const char *s;
+ mrb_int i, len;
+
+ s = mrb_sym2name_len(mrb, iv_name, &len);
+ if (len < 2) return FALSE;
+ if (s[0] != '@') return FALSE;
+ if (s[1] == '@') return FALSE;
+ for (i=1; i<len; i++) {
+ if (!identchar(s[i])) return FALSE;
+ }
+ return TRUE;
+}
+
+MRB_API void
+mrb_iv_check(mrb_state *mrb, mrb_sym iv_name)
+{
+ if (!mrb_iv_p(mrb, iv_name)) {
+ mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name));
+ }
+}
+
+MRB_API void
mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
{
struct RObject *d = mrb_obj_ptr(dest);
@@ -552,6 +578,7 @@ mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
d->iv = 0;
}
if (s->iv) {
+ mrb_write_barrier(mrb, (struct RBasic*)d);
d->iv = iv_copy(mrb, s->iv);
}
}
@@ -582,7 +609,7 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
else {
ins = mrb_inspect(mrb, v);
}
- mrb_str_append(mrb, str, ins);
+ mrb_str_cat_str(mrb, str, ins);
return 0;
}
@@ -608,7 +635,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
return mrb_any_to_s(mrb, mrb_obj_value(obj));
}
-mrb_value
+MRB_API mrb_value
mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
{
if (obj_iv_p(obj)) {
@@ -728,34 +755,46 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
return ary;
}
-mrb_value
+MRB_API mrb_value
mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym)
{
struct RClass * cls = c;
+ mrb_value v;
while (c) {
- if (c->iv) {
- iv_tbl *t = c->iv;
- mrb_value v;
-
- if (iv_get(mrb, t, sym, &v))
- return v;
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ return v;
}
c = c->super;
}
+ if (cls && cls->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
+ mrb_intern_lit(mrb, "__attached__"));
+ c = mrb_class_ptr(klass);
+ if (c->tt == MRB_TT_CLASS) {
+ while (c) {
+ if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
+ return v;
+ }
+ c = c->super;
+ }
+ }
+ }
mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
mrb_sym2str(mrb, sym), mrb_obj_value(cls));
/* not reached */
return mrb_nil_value();
}
-mrb_value
+MRB_API mrb_value
mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym);
}
-void
+MRB_API void
mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
{
struct RClass * cls = c;
@@ -781,13 +820,13 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
iv_put(mrb, cls->iv, sym, v);
}
-void
+MRB_API void
mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
{
mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v);
}
-mrb_bool
+MRB_API mrb_bool
mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
{
while (c) {
@@ -801,7 +840,7 @@ mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
return FALSE;
}
-mrb_bool
+MRB_API mrb_bool
mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym);
@@ -826,16 +865,6 @@ mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
mrb_mod_cv_set(mrb, c, sym, v);
}
-mrb_bool
-mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
-{
- struct RClass *m = mrb_class_ptr(mod);
- iv_tbl *t = m->iv;
-
- if (!t) return FALSE;
- return iv_get(mrb, t, sym, NULL);
-}
-
static void
mod_const_check(mrb_state *mrb, mrb_value mod)
{
@@ -856,7 +885,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
struct RClass *c = base;
mrb_value v;
iv_tbl *t;
- mrb_bool retry = 0;
+ mrb_bool retry = FALSE;
mrb_value name;
L_RETRY:
@@ -870,14 +899,14 @@ L_RETRY:
}
if (!retry && base && base->tt == MRB_TT_MODULE) {
c = mrb->object_class;
- retry = 1;
+ retry = TRUE;
goto L_RETRY;
}
name = mrb_symbol_value(sym);
return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name);
}
-mrb_value
+MRB_API mrb_value
mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
mod_const_check(mrb, mod);
@@ -897,6 +926,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
return v;
}
+ if (c->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+ klass = mrb_obj_iv_get(mrb, (struct RObject *)c,
+ mrb_intern_lit(mrb, "__attached__"));
+ c2 = mrb_class_ptr(klass);
+ if (c2->tt == MRB_TT_CLASS)
+ c = c2;
+ }
c2 = c;
for (;;) {
c2 = mrb_class_outer_module(mrb, c2);
@@ -909,14 +946,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
return const_get(mrb, c, sym);
}
-void
+MRB_API void
mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
{
mod_const_check(mrb, mod);
mrb_iv_set(mrb, mod, sym, v);
}
- void
+void
mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
{
struct RClass *c = mrb->c->ci->proc->target_class;
@@ -925,20 +962,20 @@ mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
}
-void
+MRB_API void
mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
mod_const_check(mrb, mod);
mrb_iv_remove(mrb, mod, sym);
}
-void
+MRB_API void
mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
{
mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v);
}
-void
+MRB_API void
mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val)
{
mrb_define_const(mrb, mrb->object_class, name, val);
@@ -986,7 +1023,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod)
return ary;
}
-mrb_value
+MRB_API mrb_value
mrb_gv_get(mrb_state *mrb, mrb_sym sym)
{
mrb_value v;
@@ -999,7 +1036,7 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym)
return mrb_nil_value();
}
-void
+MRB_API void
mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
{
iv_tbl *t;
@@ -1013,7 +1050,7 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
iv_put(mrb, t, sym, v);
}
-void
+MRB_API void
mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
{
if (!mrb->globals) {
@@ -1063,9 +1100,10 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self)
}
static mrb_bool
-mrb_const_defined_0(mrb_state *mrb, struct RClass *klass, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
+mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
{
- struct RClass * tmp;
+ struct RClass *klass = mrb_class_ptr(mod);
+ struct RClass *tmp;
mrb_bool mod_retry = 0;
tmp = klass;
@@ -1085,13 +1123,19 @@ retry:
return FALSE;
}
-int
-mrb_const_defined_at(mrb_state *mrb, struct RClass *klass, mrb_sym id)
+MRB_API mrb_bool
+mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id)
{
- return mrb_const_defined_0(mrb, klass, id, TRUE, FALSE);
+ return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE);
}
-mrb_value
+MRB_API mrb_bool
+mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id)
+{
+ return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE);
+}
+
+MRB_API mrb_value
mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id)
{
return mrb_iv_get(mrb, obj, id);
diff --git a/src/version.c b/src/version.c
index 7aac44d62..5bcecb3aa 100644
--- a/src/version.c
+++ b/src/version.c
@@ -1,12 +1,16 @@
-#include "mruby.h"
-#include "mruby/variable.h"
+#include <mruby.h>
+#include <mruby/variable.h>
void
mrb_init_version(mrb_state* mrb)
{
+ mrb_value mruby_version = mrb_str_new_lit(mrb, MRUBY_VERSION);
+
mrb_define_global_const(mrb, "RUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_RUBY_VERSION));
mrb_define_global_const(mrb, "RUBY_ENGINE", mrb_str_new_lit(mrb, MRUBY_RUBY_ENGINE));
+ mrb_define_global_const(mrb, "RUBY_ENGINE_VERSION", mruby_version);
mrb_define_global_const(mrb, "MRUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_VERSION));
+ mrb_define_global_const(mrb, "MRUBY_RELEASE_NO", mrb_fixnum_value(MRUBY_RELEASE_NO));
mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE));
mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION));
mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT));
diff --git a/src/vm.c b/src/vm.c
index 9a0f03aba..391646017 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1,4 +1,4 @@
- /*
+/*
** vm.c - virtual machine for mruby
**
** See Copyright Notice in mruby.h
@@ -7,22 +7,22 @@
#include <stddef.h>
#include <stdarg.h>
#include <math.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/hash.h"
-#include "mruby/irep.h"
-#include "mruby/numeric.h"
-#include "mruby/proc.h"
-#include "mruby/range.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/error.h"
-#include "mruby/opcode.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/hash.h>
+#include <mruby/irep.h>
+#include <mruby/numeric.h>
+#include <mruby/proc.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/opcode.h>
#include "value_array.h"
-#include "mrb_throw.h"
+#include <mruby/throw.h>
-#ifndef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
#if defined(__cplusplus)
extern "C" {
#endif
@@ -32,20 +32,6 @@ void abort(void);
#endif
#endif
-#define SET_TRUE_VALUE(r) MRB_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#define SET_FALSE_VALUE(r) MRB_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_NIL_VALUE(r) MRB_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_INT_VALUE(r,n) MRB_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
-#define SET_SYM_VALUE(r,v) MRB_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) MRB_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#ifdef MRB_NAN_BOXING
-#define SET_FLT_VALUE(mrb,r,v) r.f = (v)
-#elif defined(MRB_WORD_BOXING)
-#define SET_FLT_VALUE(mrb,r,v) r = mrb_float_value(mrb, (v))
-#else
-#define SET_FLT_VALUE(mrb,r,v) MRB_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v))
-#endif
-
#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32
@@ -66,10 +52,7 @@ The value below allows about 60000 recursive calls in the simplest case. */
# define DEBUG(x)
#endif
-#define TO_STR(x) TO_STR_(x)
-#define TO_STR_(x) #x
-
-#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)
+#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
static inline void
stack_clear(mrb_value *from, size_t count)
@@ -174,7 +157,7 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep)
to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
if (size > MRB_STACK_MAX) {
init_new_stack_space(mrb, room, keep);
- mrb_raise(mrb, E_RUNTIME_ERROR, "stack level too deep. (limit=" TO_STR(MRB_STACK_MAX) ")");
+ mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
}
}
@@ -237,14 +220,13 @@ cipush(mrb_state *mrb)
int ridx = ci->ridx;
if (ci + 1 == c->ciend) {
- size_t size = ci - c->cibase;
+ ptrdiff_t size = ci - c->cibase;
c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2);
c->ci = c->cibase + size;
c->ciend = c->cibase + size * 2;
}
ci = ++c->ci;
- ci->nregs = 2; /* protect method_missing arg and block */
ci->eidx = eidx;
ci->ridx = ridx;
ci->env = 0;
@@ -270,6 +252,7 @@ cipop(mrb_state *mrb)
stack_copy(p, e->stack, len);
}
e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
}
c->ci--;
@@ -283,6 +266,7 @@ ecall(mrb_state *mrb, int i)
mrb_value *self = mrb->c->stack;
struct RObject *exc;
+ if (i<0) return;
p = mrb->c->ensure[i];
if (!p) return;
if (mrb->c->ci->eidx > i)
@@ -306,49 +290,34 @@ ecall(mrb_state *mrb, int i)
#define MRB_FUNCALL_ARGC_MAX 16
#endif
-mrb_value
+MRB_API mrb_value
mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...)
{
+ mrb_value argv[MRB_FUNCALL_ARGC_MAX];
+ va_list ap;
+ mrb_int i;
mrb_sym mid = mrb_intern_cstr(mrb, name);
- if (argc == 0) {
- return mrb_funcall_argv(mrb, self, mid, 0, 0);
- }
- else if (argc == 1) {
- mrb_value v;
- va_list ap;
-
- va_start(ap, argc);
- v = va_arg(ap, mrb_value);
- va_end(ap);
- return mrb_funcall_argv(mrb, self, mid, 1, &v);
+ if (argc > MRB_FUNCALL_ARGC_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")");
}
- else {
- mrb_value argv[MRB_FUNCALL_ARGC_MAX];
- va_list ap;
- mrb_int i;
-
- if (argc > MRB_FUNCALL_ARGC_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" TO_STR(MRB_FUNCALL_ARGC_MAX) ")");
- }
- va_start(ap, argc);
- for (i = 0; i < argc; i++) {
- argv[i] = va_arg(ap, mrb_value);
- }
- va_end(ap);
- return mrb_funcall_argv(mrb, self, mid, argc, argv);
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++) {
+ argv[i] = va_arg(ap, mrb_value);
}
+ va_end(ap);
+ return mrb_funcall_argv(mrb, self, mid, argc, argv);
}
-mrb_value
+MRB_API mrb_value
mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk)
{
mrb_value val;
if (!mrb->jmp) {
struct mrb_jmpbuf c_jmp;
- mrb_callinfo *old_ci = mrb->c->ci;
+ ptrdiff_t nth_ci = mrb->c->ci - mrb->c->cibase;
MRB_TRY(&c_jmp) {
mrb->jmp = &c_jmp;
@@ -357,7 +326,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
mrb->jmp = 0;
}
MRB_CATCH(&c_jmp) { /* error */
- while (old_ci != mrb->c->ci) {
+ while (nth_ci < (mrb->c->ci - mrb->c->cibase)) {
mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
@@ -372,6 +341,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
mrb_sym undef = 0;
mrb_callinfo *ci;
int n;
+ ptrdiff_t voff = -1;
if (!mrb->c->stack) {
stack_init(mrb);
@@ -395,6 +365,9 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->argc = argc;
ci->target_class = c;
mrb->c->stack = mrb->c->stack + n;
+ if (mrb->c->stbase <= argv && argv < mrb->c->stend) {
+ voff = argv - mrb->c->stbase;
+ }
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
stack_extend(mrb, ci->nregs, 0);
@@ -403,6 +376,9 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
ci->nregs = p->body.irep->nregs + n;
stack_extend(mrb, ci->nregs, argc+2);
}
+ if (voff >= 0) {
+ argv = mrb->c->stbase + voff;
+ }
mrb->c->stack[0] = self;
if (undef) {
mrb->c->stack[1] = mrb_symbol_value(undef);
@@ -433,7 +409,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
return val;
}
-mrb_value
+MRB_API mrb_value
mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv)
{
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
@@ -458,7 +434,7 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
* k = Klass.new
* k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
*/
-mrb_value
+MRB_API mrb_value
mrb_f_send(mrb_state *mrb, mrb_value self)
{
mrb_sym name;
@@ -497,8 +473,16 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
return p->body.func(mrb, self);
}
+ if (ci->argc < 0) {
+ stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
+ }
+ else {
+ stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
+ }
+
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
+ ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
@@ -513,6 +497,9 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
struct RProc *p;
mrb_callinfo *ci;
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
@@ -525,6 +512,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
}
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
+ ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
@@ -599,7 +587,7 @@ mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
return eval_under(mrb, self, b, c);
}
-mrb_value
+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)
{
struct RProc *p;
@@ -646,7 +634,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
return val;
}
-mrb_value
+MRB_API mrb_value
mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
{
struct RProc *p = mrb_proc_ptr(b);
@@ -654,7 +642,7 @@ mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
}
-mrb_value
+MRB_API mrb_value
mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
{
struct RProc *p = mrb_proc_ptr(b);
@@ -705,7 +693,7 @@ argnum_error(mrb_state *mrb, mrb_int num)
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0;
-#ifdef ENABLE_DEBUG
+#ifdef MRB_ENABLE_DEBUG_HOOK
#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
#else
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
@@ -734,12 +722,11 @@ argnum_error(mrb_state *mrb, mrb_int num)
#endif
-mrb_value mrb_gv_val_get(mrb_state *mrb, mrb_sym sym);
-void mrb_gv_val_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
-
#define CALL_MAXARGS 127
-mrb_value
+void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
+
+MRB_API mrb_value
mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
/* mrb_assert(mrb_proc_cfunc_p(proc)) */
@@ -1046,7 +1033,7 @@ RETRY_TRY_BLOCK:
mrb_callinfo *ci = mrb->c->ci;
int n, eidx = ci->eidx;
- for (n=0; n<a && eidx > ci[-1].eidx; n++) {
+ for (n=0; n<a && (ci == mrb->c->cibase || eidx > ci[-1].eidx); n++) {
ecall(mrb, --eidx);
ARENA_RESTORE(mrb, ai);
}
@@ -1090,9 +1077,21 @@ RETRY_TRY_BLOCK:
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
mrb_value sym = mrb_symbol_value(mid);
+ mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
- mid = mrb_intern_lit(mrb, "method_missing");
- m = mrb_method_search_vm(mrb, &c, mid);
+ m = mrb_method_search_vm(mrb, &c, missing);
+ if (!m) {
+ mrb_value args;
+
+ if (n == CALL_MAXARGS) {
+ args = regs[a+1];
+ }
+ else {
+ args = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ }
+ mrb_method_missing(mrb, mid, recv, args);
+ }
+ mid = missing;
if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym);
}
@@ -1107,12 +1106,7 @@ RETRY_TRY_BLOCK:
ci->mid = mid;
ci->proc = m;
ci->stackent = mrb->c->stack;
- if (c->tt == MRB_TT_ICLASS) {
- ci->target_class = c->c;
- }
- else {
- ci->target_class = c;
- }
+ ci->target_class = c;
ci->pc = pc + 1;
ci->acc = a;
@@ -1243,6 +1237,13 @@ RETRY_TRY_BLOCK:
int a = GETARG_A(i);
int n = GETARG_C(i);
+ if (mid == 0) {
+ mrb_value exc;
+
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+ mrb->exc = mrb_obj_ptr(exc);
+ goto L_RAISE;
+ }
recv = regs[0];
c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
@@ -1277,6 +1278,12 @@ RETRY_TRY_BLOCK:
mrb->c->stack[0] = recv;
if (MRB_PROC_CFUNC_P(m)) {
+ if (n == CALL_MAXARGS) {
+ ci->nregs = 3;
+ }
+ else {
+ ci->nregs = n + 2;
+ }
mrb->c->stack[0] = m->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
@@ -1322,6 +1329,7 @@ RETRY_TRY_BLOCK:
struct REnv *e = uvenv(mrb, lv-1);
if (!e) {
mrb_value exc;
+
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
@@ -1364,14 +1372,14 @@ RETRY_TRY_BLOCK:
/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
/* number of optional arguments times OP_JMP should follow */
mrb_aspec ax = GETARG_Ax(i);
- int m1 = (ax>>18)&0x1f;
- int o = (ax>>13)&0x1f;
- int r = (ax>>12)&0x1;
- int m2 = (ax>>7)&0x1f;
+ int m1 = MRB_ASPEC_REQ(ax);
+ int o = MRB_ASPEC_OPT(ax);
+ int r = MRB_ASPEC_REST(ax);
+ int m2 = MRB_ASPEC_POST(ax);
/* unused
- int k = (ax>>2)&0x1f;
- int kd = (ax>>1)&0x1;
- int b = (ax>>0)& 0x1;
+ int k = MRB_ASPEC_KEY(ax);
+ int kd = MRB_ASPEC_KDICT(ax);
+ int b = MRB_ASPEC_BLOCK(ax);
*/
int argc = mrb->c->ci->argc;
mrb_value *argv = regs+1;
@@ -1478,9 +1486,6 @@ RETRY_TRY_BLOCK:
if (ci->ridx == 0) goto L_STOP;
goto L_RESCUE;
}
- while (eidx > ci[-1].eidx) {
- ecall(mrb, --eidx);
- }
while (ci[0].ridx == ci[-1].ridx) {
cipop(mrb);
ci = mrb->c->ci;
@@ -1489,12 +1494,10 @@ RETRY_TRY_BLOCK:
mrb->jmp = prev_jmp;
MRB_THROW(prev_jmp);
}
- if (ci > mrb->c->cibase) {
- while (eidx > ci[-1].eidx) {
+ if (ci == mrb->c->cibase) {
+ while (eidx > 0) {
ecall(mrb, --eidx);
}
- }
- else if (ci == mrb->c->cibase) {
if (ci->ridx == 0) {
if (mrb->c == mrb->root_c) {
regs = mrb->c->stack = mrb->c->stbase;
@@ -1510,6 +1513,12 @@ RETRY_TRY_BLOCK:
}
break;
}
+ /* call ensure only when we skip this callinfo */
+ if (ci[0].ridx == ci[-1].ridx) {
+ while (eidx > ci[-1].eidx) {
+ ecall(mrb, --eidx);
+ }
+ }
}
L_RESCUE:
if (ci->ridx == 0) goto L_STOP;
@@ -1540,6 +1549,7 @@ RETRY_TRY_BLOCK:
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
+ mrb->c->stack = mrb->c->ci->stackent;
mrb->c->ci = ci;
break;
}
@@ -1574,6 +1584,7 @@ RETRY_TRY_BLOCK:
c->prev = NULL;
}
ci = mrb->c->ci;
+ mrb->c->stack = ci->stackent;
mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
while (ci > mrb->c->ci) {
if (ci[-1].acc == CI_ACC_SKIP) {
@@ -1695,18 +1706,9 @@ RETRY_TRY_BLOCK:
NEXT;
}
-#define attr_i value.i
-#ifdef MRB_NAN_BOXING
-#define attr_f f
-#elif defined(MRB_WORD_BOXING)
-#define attr_f value.fp->f
-#else
-#define attr_f value.f
-#endif
-
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
#define OP_MATH_BODY(op,v1,v2) do {\
- regs[a].v1 = regs[a].v1 op regs[a+1].v2;\
+ v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
} while(0)
CASE(OP_ADD) {
@@ -1723,7 +1725,7 @@ RETRY_TRY_BLOCK:
x = mrb_fixnum(regs_a[0]);
y = mrb_fixnum(regs_a[1]);
if (mrb_int_add_overflow(x, y, &z)) {
- SET_FLT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
break;
}
SET_INT_VALUE(regs[a], z);
@@ -1733,7 +1735,7 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y);
}
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
@@ -1741,10 +1743,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], x + y);
}
#else
- OP_MATH_BODY(+,attr_f,attr_i);
+ OP_MATH_BODY(+,mrb_float,mrb_fixnum);
#endif
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
@@ -1752,10 +1754,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], x + y);
}
#else
- OP_MATH_BODY(+,attr_f,attr_f);
+ OP_MATH_BODY(+,mrb_float,mrb_float);
#endif
break;
case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
@@ -1781,7 +1783,7 @@ RETRY_TRY_BLOCK:
x = mrb_fixnum(regs[a]);
y = mrb_fixnum(regs[a+1]);
if (mrb_int_sub_overflow(x, y, &z)) {
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
break;
}
SET_INT_VALUE(regs[a], z);
@@ -1791,7 +1793,7 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y);
}
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
@@ -1799,10 +1801,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], x - y);
}
#else
- OP_MATH_BODY(-,attr_f,attr_i);
+ OP_MATH_BODY(-,mrb_float,mrb_fixnum);
#endif
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
@@ -1810,10 +1812,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], x - y);
}
#else
- OP_MATH_BODY(-,attr_f,attr_f);
+ OP_MATH_BODY(-,mrb_float,mrb_float);
#endif
break;
default:
@@ -1842,7 +1844,7 @@ RETRY_TRY_BLOCK:
break;
case MRB_TT_FLOAT:
{
- SET_FLT_VALUE(mrb, regs[a], mrb_float(z));
+ SET_FLOAT_VALUE(mrb, regs[a], mrb_float(z));
}
break;
default:
@@ -1855,7 +1857,7 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y);
}
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
@@ -1863,10 +1865,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], x * y);
}
#else
- OP_MATH_BODY(*,attr_f,attr_i);
+ OP_MATH_BODY(*,mrb_float,mrb_fixnum);
#endif
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
@@ -1874,10 +1876,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], x * y);
}
#else
- OP_MATH_BODY(*,attr_f,attr_f);
+ OP_MATH_BODY(*,mrb_float,mrb_float);
#endif
break;
default:
@@ -1896,14 +1898,14 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / y);
}
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
@@ -1911,10 +1913,10 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], x / y);
}
#else
- OP_MATH_BODY(/,attr_f,attr_i);
+ OP_MATH_BODY(/,mrb_float,mrb_fixnum);
#endif
break;
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
@@ -1922,18 +1924,18 @@ RETRY_TRY_BLOCK:
{
mrb_float x = mrb_float(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], x / y);
}
#else
- OP_MATH_BODY(/,attr_f,attr_f);
+ OP_MATH_BODY(/,mrb_float,mrb_float);
#endif
break;
default:
goto L_SEND;
}
#ifdef MRB_NAN_BOXING
- if (isnan(regs[a].attr_f)) {
- regs[a] = mrb_float_value(mrb, regs[a].attr_f);
+ if (isnan(mrb_float(regs[a]))) {
+ regs[a] = mrb_float_value(mrb, mrb_float(regs[a]));
}
#endif
NEXT;
@@ -1947,25 +1949,25 @@ RETRY_TRY_BLOCK:
switch (mrb_type(regs[a])) {
case MRB_TT_FIXNUM:
{
- mrb_int x = regs[a].attr_i;
+ mrb_int x = mrb_fixnum(regs[a]);
mrb_int y = GETARG_C(i);
mrb_int z;
if (mrb_int_add_overflow(x, y, &z)) {
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
break;
}
- regs[a].attr_i = z;
+ SET_INT_VALUE(regs[a], z);
}
break;
case MRB_TT_FLOAT:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLT_VALUE(mrb, regs[a], x + GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i));
}
#else
- regs[a].attr_f += GETARG_C(i);
+ mrb_float(regs[a]) += GETARG_C(i);
#endif
break;
default:
@@ -1985,15 +1987,15 @@ RETRY_TRY_BLOCK:
switch (mrb_type(regs_a[0])) {
case MRB_TT_FIXNUM:
{
- mrb_int x = regs_a[0].attr_i;
+ mrb_int x = mrb_fixnum(regs_a[0]);
mrb_int y = GETARG_C(i);
mrb_int z;
if (mrb_int_sub_overflow(x, y, &z)) {
- SET_FLT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
}
else {
- regs_a[0].attr_i = z;
+ SET_INT_VALUE(regs_a[0], z);
}
}
break;
@@ -2001,10 +2003,10 @@ RETRY_TRY_BLOCK:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLT_VALUE(mrb, regs[a], x - GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i));
}
#else
- regs_a[0].attr_f -= GETARG_C(i);
+ mrb_float(regs_a[0]) -= GETARG_C(i);
#endif
break;
default:
@@ -2015,23 +2017,23 @@ RETRY_TRY_BLOCK:
NEXT;
}
-#define OP_CMP_BODY(op,v1,v2) (regs[a].v1 op regs[a+1].v2)
+#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
#define OP_CMP(op) do {\
int result;\
/* need to check if - is overridden */\
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
- result = OP_CMP_BODY(op,attr_i,attr_i);\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
break;\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
- result = OP_CMP_BODY(op,attr_i,attr_f);\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\
break;\
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
- result = OP_CMP_BODY(op,attr_f,attr_i);\
+ result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\
break;\
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
- result = OP_CMP_BODY(op,attr_f,attr_f);\
+ result = OP_CMP_BODY(op,mrb_float,mrb_float);\
break;\
default:\
goto L_SEND;\
@@ -2138,33 +2140,28 @@ RETRY_TRY_BLOCK:
int pre = GETARG_B(i);
int post = GETARG_C(i);
+ struct RArray *ary;
+ int len, idx;
+
if (!mrb_array_p(v)) {
- regs[a++] = mrb_ary_new_capa(mrb, 0);
+ v = mrb_ary_new_from_values(mrb, 1, &regs[a]);
+ }
+ ary = mrb_ary_ptr(v);
+ len = ary->len;
+ if (len > pre + post) {
+ regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
while (post--) {
- SET_NIL_VALUE(regs[a]);
- a++;
+ regs[a++] = ary->ptr[len-post-1];
}
}
else {
- struct RArray *ary = mrb_ary_ptr(v);
- int len = ary->len;
- int i;
-
- if (len > pre + post) {
- regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
- while (post--) {
- regs[a++] = ary->ptr[len-post-1];
- }
+ regs[a++] = mrb_ary_new_capa(mrb, 0);
+ for (idx=0; idx+pre<len; idx++) {
+ regs[a+idx] = ary->ptr[pre+idx];
}
- else {
- regs[a++] = mrb_ary_new_capa(mrb, 0);
- for (i=0; i+pre<len; i++) {
- regs[a+i] = ary->ptr[pre+i];
- }
- while (i < post) {
- SET_NIL_VALUE(regs[a+i]);
- i++;
- }
+ while (idx < post) {
+ SET_NIL_VALUE(regs[a+idx]);
+ idx++;
}
}
ARENA_RESTORE(mrb, ai);
@@ -2181,6 +2178,7 @@ RETRY_TRY_BLOCK:
CASE(OP_STRCAT) {
/* A B R(A).concat(R(B)) */
mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
+ regs = mrb->c->stack;
NEXT;
}
@@ -2282,6 +2280,7 @@ RETRY_TRY_BLOCK:
ci->proc = p;
if (MRB_PROC_CFUNC_P(p)) {
+ ci->nregs = 0;
mrb->c->stack[0] = p->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
@@ -2306,8 +2305,9 @@ RETRY_TRY_BLOCK:
/* A B R(A).newmethod(Syms(B),R(A+1)) */
int a = GETARG_A(i);
struct RClass *c = mrb_class_ptr(regs[a]);
+ struct RProc *p = mrb_proc_ptr(regs[a+1]);
- mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]);
+ mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], p);
ARENA_RESTORE(mrb, ai);
NEXT;
}
@@ -2340,10 +2340,10 @@ RETRY_TRY_BLOCK:
CASE(OP_DEBUG) {
/* A B C debug print R(A),R(B),R(C) */
-#ifdef ENABLE_DEBUG
+#ifdef MRB_ENABLE_DEBUG_HOOK
mrb->debug_op_hook(mrb, irep, pc, regs);
#else
-#ifdef ENABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
#else
abort();
@@ -2395,13 +2395,13 @@ RETRY_TRY_BLOCK:
MRB_END_EXC(&c_jmp);
}
-mrb_value
+MRB_API mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
-mrb_value
+MRB_API mrb_value
mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
{
mrb_callinfo *ci;
@@ -2411,6 +2411,7 @@ mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_kee
return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
}
ci = cipush(mrb);
+ ci->nregs = 1; /* protect the receiver */
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
@@ -2419,7 +2420,7 @@ mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_kee
return v;
}
-mrb_value
+MRB_API mrb_value
mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
{
return mrb_toplevel_run_keep(mrb, proc, 0);