class.c 56.5 KB
Newer Older
mimaki's avatar
mimaki committed
1 2
/*
** class.c - Class class
roco's avatar
roco committed
3
**
mimaki's avatar
mimaki committed
4 5 6
** See Copyright Notice in mruby.h
*/

cremno's avatar
cremno committed
7 8
#include <stdarg.h>
#include "mruby.h"
9
#include "mruby/array.h"
mimaki's avatar
mimaki committed
10
#include "mruby/class.h"
11
#include "mruby/numeric.h"
mimaki's avatar
mimaki committed
12 13
#include "mruby/proc.h"
#include "mruby/string.h"
14
#include "mruby/variable.h"
15
#include "mruby/error.h"
16
#include "mruby/data.h"
mimaki's avatar
mimaki committed
17

18
KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
mimaki's avatar
mimaki committed
19 20 21 22 23 24 25 26 27

void
mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
{
  khiter_t k;
  khash_t(mt) *h = c->mt;

  if (!h) return;
  for (k = kh_begin(h); k != kh_end(h); k++) {
yui-knk's avatar
yui-knk committed
28
    if (kh_exist(h, k)) {
mimaki's avatar
mimaki committed
29 30
      struct RProc *m = kh_value(h, k);
      if (m) {
MATSUMOTO Ryosuke's avatar
MATSUMOTO Ryosuke committed
31
        mrb_gc_mark(mrb, (struct RBasic*)m);
mimaki's avatar
mimaki committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
      }
    }
  }
}

size_t
mrb_gc_mark_mt_size(mrb_state *mrb, struct RClass *c)
{
  khash_t(mt) *h = c->mt;

  if (!h) return 0;
  return kh_size(h);
}

void
mrb_gc_free_mt(mrb_state *mrb, struct RClass *c)
{
49
  kh_destroy(mt, mrb, c->mt);
mimaki's avatar
mimaki committed
50 51
}

52 53
static void
name_class(mrb_state *mrb, struct RClass *c, mrb_sym name)
mimaki's avatar
mimaki committed
54 55
{
  mrb_obj_iv_set(mrb, (struct RObject*)c,
56
                 mrb_intern_lit(mrb, "__classid__"), mrb_symbol_value(name));
mimaki's avatar
mimaki committed
57
}
take_cheeze's avatar
take_cheeze committed
58

59 60 61 62 63 64 65 66 67 68 69
static void
setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id)
{
  name_class(mrb, c, id);
  mrb_obj_iv_set(mrb, (struct RObject*)outer, id, mrb_obj_value(c));
  if (outer != mrb->object_class) {
    mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"),
                   mrb_obj_value(outer));
  }
}

70 71
#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c))

mimaki's avatar
mimaki committed
72
static void
73
prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
mimaki's avatar
mimaki committed
74
{
75
  struct RClass *sc, *c;
mimaki's avatar
mimaki committed
76

77
  if (o->c->tt == MRB_TT_SCLASS) return;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
78
  sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
79
  sc->origin = sc;
mimaki's avatar
mimaki committed
80
  sc->mt = 0;
81
  sc->iv = 0;
82 83
  if (o->tt == MRB_TT_CLASS) {
    c = (struct RClass*)o;
84 85 86 87
    if (!c->super) {
      sc->super = mrb->class_class;
    }
    else {
88 89
      sc->super = c->super->c;
    }
90
  }
91 92
  else if (o->tt == MRB_TT_SCLASS) {
    c = (struct RClass*)o;
93 94
    while (c->super->tt == MRB_TT_ICLASS)
      c = c->super;
95
    make_metaclass(mrb, c->super);
96 97
    sc->super = c->super->c;
  }
98 99 100 101 102 103
  else {
    sc->super = o->c;
  }
  o->c = sc;
  mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
  mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
104
  mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o));
mimaki's avatar
mimaki committed
105 106
}

107 108
static struct RClass *
class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
mimaki's avatar
mimaki committed
109
{
110
  mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
mimaki's avatar
mimaki committed
111

112 113
  mrb_check_type(mrb, c, MRB_TT_CLASS);
  return mrb_class_ptr(c);
mimaki's avatar
mimaki committed
114 115
}

116 117
static struct RClass *
module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id)
mimaki's avatar
mimaki committed
118
{
119
  mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id);
mimaki's avatar
mimaki committed
120

121 122
  mrb_check_type(mrb, c, MRB_TT_MODULE);
  return mrb_class_ptr(c);
mimaki's avatar
mimaki committed
123 124
}

125
MRB_API struct RClass*
mimaki's avatar
mimaki committed
126 127 128 129
mrb_class_outer_module(mrb_state *mrb, struct RClass *c)
{
  mrb_value outer;

130
  outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
131
  if (mrb_nil_p(outer)) return NULL;
mimaki's avatar
mimaki committed
132 133 134
  return mrb_class_ptr(outer);
}

135 136 137 138 139 140 141 142 143 144 145 146 147
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));
  }
}

148 149 150 151 152
static struct RClass*
define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer)
{
  struct RClass *m;

153
  if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
154 155 156 157 158 159 160 161
    return module_from_sym(mrb, outer, name);
  }
  m = mrb_module_new(mrb);
  setup_class(mrb, outer, m, name);

  return m;
}

162
MRB_API struct RClass*
163 164 165 166 167
mrb_define_module_id(mrb_state *mrb, mrb_sym name)
{
  return define_module(mrb, name, mrb->object_class);
}

168
MRB_API struct RClass*
169 170 171 172 173
mrb_define_module(mrb_state *mrb, const char *name)
{
  return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class);
}

174
MRB_API struct RClass*
mimaki's avatar
mimaki committed
175 176
mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id)
{
177
  check_if_class_or_module(mrb, outer);
178 179
  return define_module(mrb, id, mrb_class_ptr(outer));
}
mimaki's avatar
mimaki committed
180

181
MRB_API struct RClass*
182 183 184 185 186 187
mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
{
  mrb_sym id = mrb_intern_cstr(mrb, name);
  struct RClass * c = define_module(mrb, id, outer);

  setup_class(mrb, outer, c, id);
mimaki's avatar
mimaki committed
188 189 190
  return c;
}

191 192
static struct RClass*
define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer)
mimaki's avatar
mimaki committed
193
{
194 195
  struct RClass * c;

196
  if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
197
    c = class_from_sym(mrb, outer, name);
Blaž Hrastnik's avatar
Blaž Hrastnik committed
198
    c = c->origin;
199 200 201 202 203 204 205
    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),
                 mrb_obj_value(c->super), mrb_obj_value(super));
    }
    return c;
  }
mimaki's avatar
mimaki committed
206

207 208
  c = mrb_class_new(mrb, super);
  setup_class(mrb, outer, c, name);
mimaki's avatar
mimaki committed
209 210 211 212

  return c;
}

213
MRB_API struct RClass*
214 215 216
mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super)
{
  if (!super) {
217
    mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name));
218 219 220 221
  }
  return define_class(mrb, name, super, mrb->object_class);
}

222
MRB_API struct RClass*
mimaki's avatar
mimaki committed
223 224
mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
{
225
  return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super);
mimaki's avatar
mimaki committed
226 227
}

ksss's avatar
ksss committed
228 229 230 231 232 233 234 235
static void
mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass)
{
  if (!super)
    super = mrb->object_class;
  mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass));
}

236
MRB_API struct RClass*
mimaki's avatar
mimaki committed
237 238
mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id)
{
239 240
  struct RClass *s;
  struct RClass *c;
mimaki's avatar
mimaki committed
241

242 243
  if (!mrb_nil_p(super)) {
    if (mrb_type(super) != MRB_TT_CLASS) {
244
      mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", super);
245
    }
246
    s = mrb_class_ptr(super);
mimaki's avatar
mimaki committed
247
  }
248
  else {
249
    s = 0;
250
  }
251
  check_if_class_or_module(mrb, outer);
252
  c = define_class(mrb, id, s, mrb_class_ptr(outer));
ksss's avatar
ksss committed
253
  mrb_class_inherited(mrb, mrb_class_real(c->super), c);
mimaki's avatar
mimaki committed
254 255 256 257

  return c;
}

258
MRB_API mrb_bool
259 260
mrb_class_defined(mrb_state *mrb, const char *name)
{
261
  mrb_value sym = mrb_check_intern_cstr(mrb, name);
262 263 264 265
  if (mrb_nil_p(sym)) {
    return FALSE;
  }
  return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym));
266 267
}

268
MRB_API struct RClass *
269
mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
270
{
271
  return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
272 273
}

274
MRB_API struct RClass *
275 276
mrb_class_get(mrb_state *mrb, const char *name)
{
h2so5's avatar
h2so5 committed
277 278 279
  return mrb_class_get_under(mrb, mrb->object_class, name);
}

280
MRB_API struct RClass *
281
mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name)
h2so5's avatar
h2so5 committed
282
{
283 284 285
  return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name));
}

286
MRB_API struct RClass *
287 288 289
mrb_module_get(mrb_state *mrb, const char *name)
{
  return mrb_module_get_under(mrb, mrb->object_class, name);
290 291
}

mimaki's avatar
mimaki committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
/*!
 * Defines a class under the namespace of \a outer.
 * \param outer  a class which contains the new class.
 * \param id     name of the new class
 * \param super  a class from which the new class will derive.
 *               NULL means \c Object class.
 * \return the created class
 * \throw TypeError if the constant name \a name is already taken but
 *                  the constant is not a \c Class.
 * \throw NameError if the class is already defined but the class can not
 *                  be reopened because its superclass is not \a super.
 * \post top-level constant named \a name refers the returned class.
 *
 * \note if a class named \a name is already defined and its superclass is
 *       \a super, the function just returns the defined class.
 */
308
MRB_API struct RClass *
mimaki's avatar
mimaki committed
309 310
mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super)
{
311
  mrb_sym id = mrb_intern_cstr(mrb, name);
mimaki's avatar
mimaki committed
312 313
  struct RClass * c;

314 315
#if 0
  if (!super) {
316
    mrb_warn(mrb, "no super class for '%S::%S', Object assumed",
317
             mrb_obj_value(outer), mrb_sym2str(mrb, id));
mimaki's avatar
mimaki committed
318
  }
319 320 321
#endif
  c = define_class(mrb, id, super, outer);
  setup_class(mrb, outer, c, id);
mimaki's avatar
mimaki committed
322 323 324
  return c;
}

325
MRB_API void
mimaki's avatar
mimaki committed
326 327 328 329 330 331
mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p)
{
  khash_t(mt) *h = c->mt;
  khiter_t k;

  if (!h) h = c->mt = kh_init(mt, mrb);
332
  k = kh_put(mt, mrb, h, mid);
mimaki's avatar
mimaki committed
333
  kh_value(h, k) = p;
Masamitsu MURASE's avatar
Masamitsu MURASE committed
334 335 336
  if (p) {
    mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p);
  }
mimaki's avatar
mimaki committed
337 338
}

339
MRB_API void
340
mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec)
mimaki's avatar
mimaki committed
341 342
{
  struct RProc *p;
343
  int ai = mrb_gc_arena_save(mrb);
mimaki's avatar
mimaki committed
344 345

  p = mrb_proc_new_cfunc(mrb, func);
take_cheeze's avatar
take_cheeze committed
346
  p->target_class = c;
mimaki's avatar
mimaki committed
347
  mrb_define_method_raw(mrb, c, mid, p);
348
  mrb_gc_arena_restore(mrb, ai);
mimaki's avatar
mimaki committed
349 350
}

351
MRB_API void
352
mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
mimaki's avatar
mimaki committed
353
{
354
  mrb_define_method_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec);
mimaki's avatar
mimaki committed
355 356
}

357 358 359
/* a function to raise NotImplementedError with current method name */
MRB_API void
mrb_notimplement(mrb_state *mrb)
ksss's avatar
ksss committed
360 361 362 363 364 365 366 367
{
  const char *str;
  mrb_int len;
  mrb_callinfo *ci = mrb->c->ci;

  if (ci->mid) {
    str = mrb_sym2name_len(mrb, ci->mid, &len);
    mrb_raisef(mrb, E_NOTIMP_ERROR,
Robert Mosolgo's avatar
Robert Mosolgo committed
368
      "%S() function is unimplemented on this machine",
ksss's avatar
ksss committed
369 370
      mrb_str_new_static(mrb, str, (size_t)len));
  }
371 372 373 374 375 376 377 378
}

/* 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 */
ksss's avatar
ksss committed
379 380 381
  return mrb_nil_value();
}

382 383 384 385 386 387 388
static mrb_value
check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m)
{
  mrb_value tmp;

  tmp = mrb_check_convert_type(mrb, val, t, c, m);
  if (mrb_nil_p(tmp)) {
389
    mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c));
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
  }
  return tmp;
}

static mrb_value
to_str(mrb_state *mrb, mrb_value val)
{
  return check_type(mrb, val, MRB_TT_STRING, "String", "to_str");
}

static mrb_value
to_ary(mrb_state *mrb, mrb_value val)
{
  return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
}

static mrb_value
to_hash(mrb_state *mrb, mrb_value val)
{
  return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash");
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
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);
  }
}

427 428 429 430
/*
  retrieve arguments from mrb_state.

  mrb_get_args(mrb, format, ...)
431

432 433
  returns number of arguments parsed.

Carson McDonald's avatar
Carson McDonald committed
434
  format specifiers:
435

436 437 438
    string  mruby type     C type                 note
    ----------------------------------------------------------------------------------------------
    o:      Object         [mrb_value]
439
    C:      class/module   [mrb_value]
440
    S:      String         [mrb_value]            when ! follows the value may be nil
441 442
    A:      Array          [mrb_value]
    H:      Hash           [mrb_value]
443
    s:      String         [char*,mrb_int]        Receive two arguments.
444 445 446 447 448 449
    z:      String         [char*]                NUL terminated string.
    a:      Array          [mrb_value*,mrb_int]   Receive two arguments.
    f:      Float          [mrb_float]
    i:      Integer        [mrb_int]
    b:      Boolean        [mrb_bool]
    n:      Symbol         [mrb_sym]
450
    d:      Data           [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
451
    &:      Block          [mrb_value]
452
    *:      rest argument  [mrb_value*,mrb_int]   Receive the rest of the arguments as an array.
453
    |:      optional                              Next argument of '|' and later are optional.
454
    ?:      optional given [mrb_bool]             true if preceding argument (optional) is given.
455
 */
456
MRB_API mrb_int
mimaki's avatar
mimaki committed
457 458 459
mrb_get_args(mrb_state *mrb, const char *format, ...)
{
  char c;
460
  int i = 0;
461
  mrb_value *sp = mrb->c->stack + 1;
mimaki's avatar
mimaki committed
462
  va_list ap;
463
  int argc = mrb->c->ci->argc;
Jun Hiroe's avatar
Jun Hiroe committed
464 465
  mrb_bool opt = FALSE;
  mrb_bool given = TRUE;
mimaki's avatar
mimaki committed
466 467 468

  va_start(ap, format);
  if (argc < 0) {
469
    struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
mimaki's avatar
mimaki committed
470 471

    argc = a->len;
472
    sp = a->ptr;
mimaki's avatar
mimaki committed
473 474
  }
  while ((c = *format++)) {
475
    switch (c) {
476
    case '|': case '*': case '&': case '?':
477 478
      break;
    default:
479 480
      if (argc <= i) {
        if (opt) {
Jun Hiroe's avatar
Jun Hiroe committed
481
          given = FALSE;
482 483 484 485
        }
        else {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
        }
486
      }
487
      break;
488
    }
489

mimaki's avatar
mimaki committed
490 491 492 493
    switch (c) {
    case 'o':
      {
        mrb_value *p;
494

mimaki's avatar
mimaki committed
495
        p = va_arg(ap, mrb_value*);
skandhas's avatar
skandhas committed
496 497 498 499
        if (i < argc) {
          *p = *sp++;
          i++;
        }
mimaki's avatar
mimaki committed
500 501
      }
      break;
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    case 'C':
      {
        mrb_value *p;

        p = va_arg(ap, mrb_value*);
        if (i < argc) {
          mrb_value ss;

          ss = *sp++;
          switch (mrb_type(ss)) {
          case MRB_TT_CLASS:
          case MRB_TT_MODULE:
          case MRB_TT_SCLASS:
            break;
          default:
            mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss);
            break;
          }
          *p = ss;
          i++;
        }
      }
      break;
525
    case 'S':
mimaki's avatar
mimaki committed
526
      {
527
        mrb_value *p;
mimaki's avatar
mimaki committed
528

529
        p = va_arg(ap, mrb_value*);
530 531 532 533 534 535 536 537
        if (*format == '!') {
          format++;
          if (mrb_nil_p(*sp)) {
            *p = *sp++;
            i++;
            break;
          }
        }
skandhas's avatar
skandhas committed
538 539 540 541
        if (i < argc) {
          *p = to_str(mrb, *sp++);
          i++;
        }
542 543 544 545 546
      }
      break;
    case 'A':
      {
        mrb_value *p;
547

548
        p = va_arg(ap, mrb_value*);
skandhas's avatar
skandhas committed
549 550 551 552
        if (i < argc) {
          *p = to_ary(mrb, *sp++);
          i++;
        }
553 554 555 556 557 558 559
      }
      break;
    case 'H':
      {
        mrb_value *p;

        p = va_arg(ap, mrb_value*);
skandhas's avatar
skandhas committed
560 561 562 563
        if (i < argc) {
          *p = to_hash(mrb, *sp++);
          i++;
        }
564 565 566 567
      }
      break;
    case 's':
      {
skandhas's avatar
skandhas committed
568
        mrb_value ss;
569
        char **ps = 0;
570
        mrb_int *pl = 0;
571

skandhas's avatar
skandhas committed
572
        ps = va_arg(ap, char**);
573
        pl = va_arg(ap, mrb_int*);
skandhas's avatar
skandhas committed
574 575
        if (i < argc) {
          ss = to_str(mrb, *sp++);
576 577
          *ps = RSTRING_PTR(ss);
          *pl = RSTRING_LEN(ss);
skandhas's avatar
skandhas committed
578 579
          i++;
        }
580 581 582 583
      }
      break;
    case 'z':
      {
skandhas's avatar
skandhas committed
584
        mrb_value ss;
585
        const char **ps;
586

587
        ps = va_arg(ap, const char**);
skandhas's avatar
skandhas committed
588 589
        if (i < argc) {
          ss = to_str(mrb, *sp++);
590
          *ps = mrb_string_value_cstr(mrb, &ss);
skandhas's avatar
skandhas committed
591 592
          i++;
        }
593 594 595 596
      }
      break;
    case 'a':
      {
skandhas's avatar
skandhas committed
597
        mrb_value aa;
598 599
        struct RArray *a;
        mrb_value **pb;
600
        mrb_int *pl;
601

skandhas's avatar
skandhas committed
602
        pb = va_arg(ap, mrb_value**);
603
        pl = va_arg(ap, mrb_int*);
skandhas's avatar
skandhas committed
604 605 606 607 608 609 610
        if (i < argc) {
          aa = to_ary(mrb, *sp++);
          a = mrb_ary_ptr(aa);
          *pb = a->ptr;
          *pl = a->len;
          i++;
        }
mimaki's avatar
mimaki committed
611 612 613 614 615 616 617
      }
      break;
    case 'f':
      {
        mrb_float *p;

        p = va_arg(ap, mrb_float*);
skandhas's avatar
skandhas committed
618
        if (i < argc) {
619
          *p = mrb_to_flo(mrb, *sp);
skandhas's avatar
skandhas committed
620 621 622
          sp++;
          i++;
        }
mimaki's avatar
mimaki committed
623 624
      }
      break;
625
    case 'i':
mimaki's avatar
mimaki committed
626
      {
627
        mrb_int *p;
mimaki's avatar
mimaki committed
628

629
        p = va_arg(ap, mrb_int*);
skandhas's avatar
skandhas committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
        if (i < argc) {
          switch (mrb_type(*sp)) {
            case MRB_TT_FIXNUM:
              *p = mrb_fixnum(*sp);
              break;
            case MRB_TT_FLOAT:
              {
                mrb_float f = mrb_float(*sp);

                if (!FIXABLE(f)) {
                  mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
                }
                *p = (mrb_int)f;
              }
              break;
645
            case MRB_TT_STRING:
646
              mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer");
647
              break;
skandhas's avatar
skandhas committed
648
            default:
649
              *p = mrb_fixnum(mrb_Integer(mrb, *sp));
skandhas's avatar
skandhas committed
650 651 652 653 654
              break;
          }
          sp++;
          i++;
        }
mimaki's avatar
mimaki committed
655 656
      }
      break;
657 658
    case 'b':
      {
659
        mrb_bool *boolp = va_arg(ap, mrb_bool*);
660

skandhas's avatar
skandhas committed
661 662 663 664 665
        if (i < argc) {
          mrb_value b = *sp++;
          *boolp = mrb_test(b);
          i++;
        }
666 667
      }
      break;
668 669
    case 'n':
      {
skandhas's avatar
skandhas committed
670 671 672 673 674 675 676
        mrb_sym *symp;

        symp = va_arg(ap, mrb_sym*);
        if (i < argc) {
          mrb_value ss;

          ss = *sp++;
677
          *symp = to_sym(mrb, ss);
skandhas's avatar
skandhas committed
678 679
          i++;
        }
680 681
      }
      break;
682 683 684 685 686 687 688 689 690 691 692 693 694
    case 'd':
      {
        void** datap;
        struct mrb_data_type const* type;

        datap = va_arg(ap, void**);
        type = va_arg(ap, struct mrb_data_type const*);
        if (i < argc) {
          *datap = mrb_data_get_ptr(mrb, *sp++, type);
          ++i;
        }
      }
      break;
mimaki's avatar
mimaki committed
695 696 697

    case '&':
      {
698
        mrb_value *p, *bp;
mimaki's avatar
mimaki committed
699 700

        p = va_arg(ap, mrb_value*);
701 702
        if (mrb->c->ci->argc < 0) {
          bp = mrb->c->stack + 2;
roco's avatar
roco committed
703
        }
skandhas's avatar
skandhas committed
704
        else {
705
          bp = mrb->c->stack + mrb->c->ci->argc + 1;
skandhas's avatar
skandhas committed
706
        }
roco's avatar
roco committed
707
        *p = *bp;
mimaki's avatar
mimaki committed
708 709
      }
      break;
710
    case '|':
Jun Hiroe's avatar
Jun Hiroe committed
711
      opt = TRUE;
712
      break;
713 714 715 716 717 718 719 720
    case '?':
      {
        mrb_bool *p;

        p = va_arg(ap, mrb_bool*);
        *p = given;
      }
      break;
721

mimaki's avatar
mimaki committed
722 723 724
    case '*':
      {
        mrb_value **var;
725
        mrb_int *pl;
726

mimaki's avatar
mimaki committed
727
        var = va_arg(ap, mrb_value**);
728
        pl = va_arg(ap, mrb_int*);
roco's avatar
roco committed
729
        if (argc > i) {
730 731
          *pl = argc-i;
          if (*pl > 0) {
skandhas's avatar
skandhas committed
732
            *var = sp;
roco's avatar
roco committed
733
          }
skandhas's avatar
skandhas committed
734 735
          i = argc;
          sp += *pl;
roco's avatar
roco committed
736 737
        }
        else {
738
          *pl = 0;
roco's avatar
roco committed
739 740
          *var = NULL;
        }
mimaki's avatar
mimaki committed
741 742
      }
      break;
743
    default:
744
      mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1));
745
      break;
mimaki's avatar
mimaki committed
746 747
    }
  }
748
  if (!c && argc > i) {
749 750
    mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
  }
mimaki's avatar
mimaki committed
751
  va_end(ap);
752
  return i;
mimaki's avatar
mimaki committed
753 754 755 756 757 758 759
}

static struct RClass*
boot_defclass(mrb_state *mrb, struct RClass *super)
{
  struct RClass *c;

Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
760
  c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
761 762 763 764 765 766 767
  if (super) {
    c->super = super;
    mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
  }
  else {
    c->super = mrb->object_class;
  }
Blaž Hrastnik's avatar
Blaž Hrastnik committed
768
  c->origin = c;
mimaki's avatar
mimaki committed
769 770 771 772
  c->mt = kh_init(mt, mrb);
  return c;
}

Blaž Hrastnik's avatar
Blaž Hrastnik committed
773
MRB_API inline void
774
include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super)
mimaki's avatar
mimaki committed
775
{
776
  while (m) {
777 778 779
    struct RClass *p = c, *ic;
    int superclass_seen = 0;

780
    if (c->mt && c->mt == m->mt) {
781 782
      mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
    }
783
    while (p) {
784
      if (c != p && p->tt == MRB_TT_CLASS) {
Blaž Hrastnik's avatar
Blaž Hrastnik committed
785
        if (!search_super) break;
skandhas's avatar
skandhas committed
786
        superclass_seen = 1;
787
      }
yui-knk's avatar
yui-knk committed
788
      else if (p->mt == m->mt) {
skandhas's avatar
skandhas committed
789 790 791 792
        if (p->tt == MRB_TT_ICLASS && !superclass_seen) {
          ins_pos = p;
        }
        goto skip;
793
      }
794 795 796 797 798 799 800 801
      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;
802
    }
803
    ic->origin = ic;
804 805 806 807 808 809 810
    ic->mt = m->mt;
    ic->iv = m->iv;
    ic->super = ins_pos->super;
    ins_pos->super = ic;
    mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic);
    ins_pos = ic;
  skip:
811 812
    m = m->super;
  }
mimaki's avatar
mimaki committed
813 814
}

Blaž Hrastnik's avatar
Blaž Hrastnik committed
815 816 817
MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
818
  include_module_at(mrb, c, c->origin, m, FALSE);
Blaž Hrastnik's avatar
Blaž Hrastnik committed
819 820 821 822 823 824 825 826 827 828 829
}

MRB_API void
mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
  struct RClass *origin;
  int changed = 0;

  origin = c->origin;
  if (origin == c) {
    origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
830
    origin->origin = origin;
Blaž Hrastnik's avatar
Blaž Hrastnik committed
831 832 833 834 835 836 837
    //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */
    origin->super = c->super;
    c->super = origin;
    c->origin = origin;
    origin->mt = c->mt;
    c->mt = kh_init(mt, mrb);
  }
838
  include_module_at(mrb, c, c, m, FALSE); // changed =
Blaž Hrastnik's avatar
Blaž Hrastnik committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
  if (changed) {
    //rb_vm_check_redefinition_by_prepend(klass);
  }
}

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;
}

mimaki's avatar
mimaki committed
873
static mrb_value
874
mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
mimaki's avatar
mimaki committed
875
{
876
  mrb_value klass;
mimaki's avatar
mimaki committed
877

878
  mrb_check_type(mrb, mod, MRB_TT_MODULE);
879
  mrb_get_args(mrb, "C", &klass);
mimaki's avatar
mimaki committed
880 881 882 883
  mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
  return mod;
}

884 885 886 887
static mrb_value
mrb_mod_include(mrb_state *mrb, mrb_value klass)
{
  mrb_value *argv;
888
  mrb_int argc, i;
889 890 891 892 893 894

  mrb_get_args(mrb, "*", &argv, &argc);
  for (i=0; i<argc; i++) {
    mrb_check_type(mrb, argv[i], MRB_TT_MODULE);
  }
  while (argc--) {
895 896
    mrb_funcall(mrb, argv[argc], "append_features", 1, klass);
    mrb_funcall(mrb, argv[argc], "included", 1, klass);
897 898 899 900 901
  }

  return klass;
}

skandhas's avatar
skandhas committed
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
/* 15.2.2.4.28 */
/*
 *  call-seq:
 *     mod.include?(module)    -> true or false
 *
 *  Returns <code>true</code> if <i>module</i> is included in
 *  <i>mod</i> or one of <i>mod</i>'s ancestors.
 *
 *     module A
 *     end
 *     class B
 *       include A
 *     end
 *     class C < B
 *     end
 *     B.include?(A)   #=> true
 *     C.include?(A)   #=> true
 *     A.include?(A)   #=> false
 */
skandhas's avatar
skandhas committed
921 922 923 924 925 926
static mrb_value
mrb_mod_include_p(mrb_state *mrb, mrb_value mod)
{
  mrb_value mod2;
  struct RClass *c = mrb_class_ptr(mod);

927
  mrb_get_args(mrb, "C", &mod2);
skandhas's avatar
skandhas committed
928 929 930 931 932 933 934 935 936 937
  mrb_check_type(mrb, mod2, MRB_TT_MODULE);

  while (c) {
    if (c->tt == MRB_TT_ICLASS) {
      if (c->c == mrb_class_ptr(mod2)) return mrb_true_value();
    }
    c = c->super;
  }
  return mrb_false_value();
}
938

939 940 941 942 943 944 945
static mrb_value
mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
{
  mrb_value result;
  struct RClass *c = mrb_class_ptr(self);

  result = mrb_ary_new(mrb);
946 947
  mrb_ary_push(mrb, result, mrb_obj_value(c));
  c = c->super;
948 949 950 951
  while (c) {
    if (c->tt == MRB_TT_ICLASS) {
      mrb_ary_push(mrb, result, mrb_obj_value(c->c));
    }
952
    else if (c->tt != MRB_TT_SCLASS) {
953 954 955 956 957 958 959 960
      mrb_ary_push(mrb, result, mrb_obj_value(c));
    }
    c = c->super;
  }

  return result;
}

961 962 963 964 965 966 967 968 969 970 971
static mrb_value
mrb_mod_extend_object(mrb_state *mrb, mrb_value mod)
{
  mrb_value obj;

  mrb_check_type(mrb, mod, MRB_TT_MODULE);
  mrb_get_args(mrb, "o", &obj);
  mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod));
  return mod;
}

972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
static mrb_value
mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
{
  mrb_value result;
  struct RClass *c = mrb_class_ptr(self);

  result = mrb_ary_new(mrb);
  while (c) {
    if (c->tt == MRB_TT_ICLASS) {
      mrb_ary_push(mrb, result, mrb_obj_value(c->c));
    }
    c = c->super;
  }

  return result;
}

989 990 991 992 993 994 995
static mrb_value
mrb_mod_initialize(mrb_state *mrb, mrb_value mod)
{
  mrb_value b;

  mrb_get_args(mrb, "&", &b);
  if (!mrb_nil_p(b)) {
ksss's avatar
ksss committed
996
    mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod));
997 998 999 1000
  }
  return mod;
}

cremno's avatar
cremno committed
1001
mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int);
skandhas's avatar
skandhas committed
1002

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
/* 15.2.2.4.33 */
/*
 *  call-seq:
 *     mod.instance_methods(include_super=true)   -> array
 *
 *  Returns an array containing the names of the public and protected instance
 *  methods in the receiver. For a module, these are the public and protected methods;
 *  for a class, they are the instance (not singleton) methods. With no
 *  argument, or with an argument that is <code>false</code>, the
 *  instance methods in <i>mod</i> are returned, otherwise the methods
 *  in <i>mod</i> and <i>mod</i>'s superclasses are returned.
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       def method2()  end
 *     end
 *     class C < B
 *       def method3()  end
 *     end
 *
 *     A.instance_methods                #=> [:method1]
 *     B.instance_methods(false)         #=> [:method2]
 *     C.instance_methods(false)         #=> [:method3]
 *     C.instance_methods(true).length   #=> 43
 */

skandhas's avatar
skandhas committed
1031 1032 1033 1034
static mrb_value
mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
{
  struct RClass *c = mrb_class_ptr(mod);
1035
  mrb_bool recur = TRUE;
h2so5's avatar
h2so5 committed
1036
  mrb_get_args(mrb, "|b", &recur);
cremno's avatar
cremno committed
1037
  return mrb_class_instance_method_list(mrb, recur, c, 0);
skandhas's avatar
skandhas committed
1038 1039
}

1040 1041
/* implementation of module_eval/class_eval */
mrb_value mrb_mod_module_eval(mrb_state*, mrb_value);
skandhas's avatar
skandhas committed
1042

1043
static mrb_value
1044 1045 1046 1047 1048
mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod)
{
  return mod;
}

1049
MRB_API mrb_value
mimaki's avatar
mimaki committed
1050 1051 1052 1053 1054 1055
mrb_singleton_class(mrb_state *mrb, mrb_value v)
{
  struct RBasic *obj;

  switch (mrb_type(v)) {
  case MRB_TT_FALSE:
1056 1057 1058
    if (mrb_nil_p(v))
      return mrb_obj_value(mrb->nil_class);
    return mrb_obj_value(mrb->false_class);
mimaki's avatar
mimaki committed
1059
  case MRB_TT_TRUE:
1060
    return mrb_obj_value(mrb->true_class);
1061
  case MRB_TT_CPTR:
1062
    return mrb_obj_value(mrb->object_class);
mimaki's avatar
mimaki committed
1063 1064 1065
  case MRB_TT_SYMBOL:
  case MRB_TT_FIXNUM:
  case MRB_TT_FLOAT:
1066 1067
    mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton");
    return mrb_nil_value();    /* not reached */
mimaki's avatar
mimaki committed
1068
  default:
roco's avatar
roco committed
1069
    break;
mimaki's avatar
mimaki committed
1070
  }
1071
  obj = mrb_basic_ptr(v);
1072
  prepare_singleton_class(mrb, obj);
1073 1074 1075 1076
  if (mrb->c && mrb->c->ci && mrb->c->ci->target_class) {
    mrb_obj_iv_set(mrb, (struct RObject*)obj->c, mrb_intern_lit(mrb, "__outer__"),
                   mrb_obj_value(mrb->c->ci->target_class));
  }
mimaki's avatar
mimaki committed
1077 1078 1079
  return mrb_obj_value(obj->c);
}

1080
MRB_API void
1081
mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, mrb_aspec aspec)
mimaki's avatar
mimaki committed
1082
{
1083
  prepare_singleton_class(mrb, (struct RBasic*)o);
1084
  mrb_define_method_id(mrb, o->c, mrb_intern_cstr(mrb, name), func, aspec);
mimaki's avatar
mimaki committed
1085 1086
}

1087
MRB_API void
1088
mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
1089
{
1090
  mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec);
1091 1092
}

1093
MRB_API void
1094
mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
1095 1096 1097 1098 1099
{
  mrb_define_class_method(mrb, c, name, func, aspec);
  mrb_define_method(mrb, c, name, func, aspec);
}

1100
MRB_API struct RProc*
mimaki's avatar
mimaki committed
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
{
  khiter_t k;
  struct RProc *m;
  struct RClass *c = *cp;

  while (c) {
    khash_t(mt) *h = c->mt;

    if (h) {
1111
      k = kh_get(mt, mrb, h, mid);
mimaki's avatar
mimaki committed
1112
      if (k != kh_end(h)) {
roco's avatar
roco committed
1113 1114 1115 1116
        m = kh_value(h, k);
        if (!m) break;
        *cp = c;
        return m;
mimaki's avatar
mimaki committed
1117 1118 1119 1120
      }
    }
    c = c->super;
  }
1121
  return NULL;                  /* no method */
mimaki's avatar
mimaki committed
1122 1123
}

1124
MRB_API struct RProc*
mimaki's avatar
mimaki committed
1125 1126 1127 1128 1129 1130
mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
{
  struct RProc *m;

  m = mrb_method_search_vm(mrb, &c, mid);
  if (!m) {
1131
    mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0);
1132
    if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) {
1133 1134
      inspect = mrb_any_to_s(mrb, mrb_obj_value(c));
    }
1135
    mrb_name_error(mrb, mid, "undefined method '%S' for class %S",
1136
               mrb_sym2str(mrb, mid), inspect);
mimaki's avatar
mimaki committed
1137 1138 1139 1140
  }
  return m;
}

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
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;
1154
  int ai;
1155 1156

  mrb_get_args(mrb, "*", &argv, &argc);
1157
  ai = mrb_gc_arena_save(mrb);
1158 1159 1160 1161 1162 1163 1164
  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);
1165
    mrb_str_cat_lit(mrb, str, "@");
1166 1167 1168 1169 1170 1171
    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));
1172
    mrb_gc_arena_restore(mrb, ai);
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
  }
  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;
1194
  int ai;
1195 1196

  mrb_get_args(mrb, "*", &argv, &argc);
1197
  ai = mrb_gc_arena_save(mrb);
1198 1199 1200 1201 1202 1203 1204 1205 1206
  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);
1207
    mrb_str_cat_lit(mrb, str, "@");
1208 1209 1210 1211 1212 1213 1214 1215
    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);
1216
    mrb_str_cat_lit(mrb, str, "=");
1217 1218 1219 1220
    method = mrb_intern_str(mrb, str);

    mrb_define_method_raw(mrb, c, method,
                          mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr));
1221
    mrb_gc_arena_restore(mrb, ai);
1222 1223 1224 1225
  }
  return mrb_nil_value();
}

1226 1227
static mrb_value
mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
mimaki's avatar
mimaki committed
1228
{
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
  struct RClass *c = mrb_class_ptr(cv);
  struct RObject *o;
  enum mrb_vtype ttype = MRB_INSTANCE_TT(c);

  if (c->tt == MRB_TT_SCLASS)
    mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class");

  if (ttype == 0) ttype = MRB_TT_OBJECT;
  o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c);
  return mrb_obj_value(o);
mimaki's avatar
mimaki committed
1239 1240 1241 1242 1243 1244
}

/*
 *  call-seq:
 *     class.new(args, ...)    ->  obj
 *
Jared Breeden's avatar
Jared Breeden committed
1245 1246 1247 1248 1249
 *  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`.
mimaki's avatar
mimaki committed
1250 1251 1252
 *
 */

1253
MRB_API mrb_value
mimaki's avatar
mimaki committed
1254 1255
mrb_instance_new(mrb_state *mrb, mrb_value cv)
{
1256
  mrb_value obj, blk;
mimaki's avatar
mimaki committed
1257
  mrb_value *argv;
1258
  mrb_int argc;
mimaki's avatar
mimaki committed
1259

1260
  mrb_get_args(mrb, "*&", &argv, &argc, &blk);
1261
  obj = mrb_instance_alloc(mrb, cv);
1262
  mrb_funcall_with_block(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv, blk);
mimaki's avatar
mimaki committed
1263 1264 1265 1266

  return obj;
}

1267
MRB_API mrb_value
1268
mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv)
Yuichiro MASUI's avatar
Yuichiro MASUI committed
1269
{
1270
  mrb_value obj;
1271

1272
  obj = mrb_instance_alloc(mrb, mrb_obj_value(c));
1273
  mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv);
1274 1275

  return obj;
Yuichiro MASUI's avatar
Yuichiro MASUI committed
1276 1277
}

1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
static mrb_value
mrb_class_initialize(mrb_state *mrb, mrb_value c)
{
  mrb_value a, b;

  mrb_get_args(mrb, "|C&", &a, &b);
  if (!mrb_nil_p(b)) {
    mrb_yield_with_class(mrb, b, 1, &c, c, mrb_class_ptr(c));
  }
  return c;
}

1290 1291 1292
static mrb_value
mrb_class_new_class(mrb_state *mrb, mrb_value cv)
{
1293
  mrb_int n;
h2so5's avatar
h2so5 committed
1294 1295
  mrb_value super, blk;
  mrb_value new_class;
take_cheeze's avatar
take_cheeze committed
1296

1297 1298
  n = mrb_get_args(mrb, "|C&", &super, &blk);
  if (n == 0) {
1299 1300
    super = mrb_obj_value(mrb->object_class);
  }
h2so5's avatar
h2so5 committed
1301
  new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
1302
  mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk);
ksss's avatar
ksss committed
1303
  mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
h2so5's avatar
h2so5 committed
1304
  return new_class;
1305 1306
}

1307
static mrb_value
1308 1309
mrb_class_superclass(mrb_state *mrb, mrb_value klass)
{
1310 1311
  struct RClass *c;

1312
  c = mrb_class_ptr(klass);
1313 1314 1315 1316 1317 1318
  c = c->super;
  while (c && c->tt == MRB_TT_ICLASS) {
    c = c->super;
  }
  if (!c) return mrb_nil_value();
  return mrb_obj_value(c);
1319 1320
}

mimaki's avatar
mimaki committed
1321 1322 1323 1324 1325 1326 1327 1328 1329
static mrb_value
mrb_bob_init(mrb_state *mrb, mrb_value cv)
{
  return mrb_nil_value();
}

static mrb_value
mrb_bob_not(mrb_state *mrb, mrb_value cv)
{
1330
  return mrb_bool_value(!mrb_test(cv));
mimaki's avatar
mimaki committed
1331 1332
}

1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
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);
}

mimaki's avatar
mimaki committed
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
/* 15.3.1.3.30 */
/*
 *  call-seq:
 *     obj.method_missing(symbol [, *args] )   -> result
 *
 *  Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
 *  <i>symbol</i> is the symbol for the method called, and <i>args</i>
 *  are any arguments that were passed to it. By default, the interpreter
 *  raises an error when this method is called. However, it is possible
 *  to override the method to provide more dynamic behavior.
 *  If it is decided that a particular method should not be handled, then
 *  <i>super</i> should be called, so that ancestors can pick up the
 *  missing method.
 *  The example below creates
 *  a class <code>Roman</code>, which responds to methods with names
 *  consisting of roman numerals, returning the corresponding integer
 *  values.
 *
 *     class Roman
 *       def romanToInt(str)
 *         # ...
 *       end
 *       def method_missing(methId)
 *         str = methId.id2name
 *         romanToInt(str)
 *       end
 *     end
 *
 *     r = Roman.new
 *     r.iv      #=> 4
 *     r.xxiii   #=> 23
 *     r.mm      #=> 2000
 */
static mrb_value
mrb_bob_missing(mrb_state *mrb, mrb_value mod)
{
1394 1395
  mrb_sym name;
  mrb_value *a;
1396
  mrb_int alen;
mimaki's avatar
mimaki committed
1397

1398
  mrb_get_args(mrb, "n*", &name, &a, &alen);
1399
  mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
mimaki's avatar
mimaki committed
1400 1401 1402 1403
  /* not reached */
  return mrb_nil_value();
}

1404
MRB_API mrb_bool
1405
mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
mimaki's avatar
mimaki committed
1406 1407 1408 1409 1410 1411 1412
{
  khiter_t k;

  while (c) {
    khash_t(mt) *h = c->mt;

    if (h) {
1413
      k = kh_get(mt, mrb, h, mid);
1414 1415
      if (k != kh_end(h)) {
        if (kh_value(h, k)) {
1416
          return TRUE;  /* method exists */
1417 1418
        }
        else {
1419
          return FALSE; /* undefined method */
1420 1421
        }
      }
mimaki's avatar
mimaki committed
1422 1423 1424
    }
    c = c->super;
  }
1425
  return FALSE;         /* no method */
mimaki's avatar
mimaki committed
1426 1427
}

1428
MRB_API mrb_bool
mimaki's avatar
mimaki committed
1429 1430
mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid)
{
1431
  return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid);
mimaki's avatar
mimaki committed
1432 1433
}

1434
MRB_API mrb_value
mimaki's avatar
mimaki committed
1435 1436 1437
mrb_class_path(mrb_state *mrb, struct RClass *c)
{
  mrb_value path;
1438
  const char *name;
1439
  mrb_sym classpath = mrb_intern_lit(mrb, "__classpath__");
mimaki's avatar
mimaki committed
1440

1441
  path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath);
mimaki's avatar
mimaki committed
1442 1443
  if (mrb_nil_p(path)) {
    struct RClass *outer = mrb_class_outer_module(mrb, c);
1444
    mrb_sym sym = mrb_class_sym(mrb, c, outer);
1445 1446
    mrb_int len;

1447 1448 1449 1450
    if (sym == 0) {
      return mrb_nil_value();
    }
    else if (outer && outer != mrb->object_class) {
mimaki's avatar
mimaki committed
1451
      mrb_value base = mrb_class_path(mrb, outer);
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
      path = mrb_str_buf_new(mrb, 0);
      if (mrb_nil_p(base)) {
        mrb_str_cat_lit(mrb, path, "#<Class:");
        mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, outer));
        mrb_str_cat_lit(mrb, path, ">");
      }
      else {
        mrb_str_concat(mrb, path, base);
      }
      mrb_str_cat_lit(mrb, path, "::");
1462
      name = mrb_sym2name_len(mrb, sym, &len);
1463
      mrb_str_cat(mrb, path, name, len);
mimaki's avatar
mimaki committed
1464 1465
    }
    else {
1466 1467
      name = mrb_sym2name_len(mrb, sym, &len);
      path = mrb_str_new(mrb, name, len);
mimaki's avatar
mimaki committed
1468
    }
1469
    mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path);
mimaki's avatar
mimaki committed
1470 1471 1472 1473
  }
  return path;
}

1474
MRB_API struct RClass *
mimaki's avatar
mimaki committed
1475 1476
mrb_class_real(struct RClass* cl)
{
ksss's avatar
ksss committed
1477
  if (cl == 0)
1478
    return NULL;
mimaki's avatar
mimaki committed
1479 1480 1481 1482 1483 1484
  while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) {
    cl = cl->super;
  }
  return cl;
}

1485
MRB_API const char*
mimaki's avatar
mimaki committed
1486 1487 1488
mrb_class_name(mrb_state *mrb, struct RClass* c)
{
  mrb_value path = mrb_class_path(mrb, c);
1489
  if (mrb_nil_p(path)) {
1490
    path = mrb_str_new_lit(mrb, "#<Class:");
1491
    mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
1492
    mrb_str_cat_lit(mrb, path, ">");
1493
  }
1494
  return RSTRING_PTR(path);
mimaki's avatar
mimaki committed
1495 1496
}

1497
MRB_API const char*
mimaki's avatar
mimaki committed
1498 1499
mrb_obj_classname(mrb_state *mrb, mrb_value obj)
{
1500
  return mrb_class_name(mrb, mrb_obj_class(mrb, obj));
mimaki's avatar
mimaki committed
1501 1502 1503 1504 1505 1506 1507 1508
}

/*!
 * Ensures a class can be derived from super.
 *
 * \param super a reference to an object.
 * \exception TypeError if \a super is not a Class or \a super is a singleton class.
 */
1509
static void
mimaki's avatar
mimaki committed
1510 1511 1512
mrb_check_inheritable(mrb_state *mrb, struct RClass *super)
{
  if (super->tt != MRB_TT_CLASS) {
1513
    mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super));
mimaki's avatar
mimaki committed
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
  }
  if (super->tt == MRB_TT_SCLASS) {
    mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class");
  }
  if (super == mrb->class_class) {
    mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of Class");
  }
}

/*!
 * Creates a new class.
 * \param super     a class from which the new class derives.
 * \exception TypeError \a super is not inheritable.
 * \exception TypeError \a super is the Class class.
1528
 */
1529
MRB_API struct RClass*
mimaki's avatar
mimaki committed
1530 1531 1532 1533 1534 1535 1536 1537
mrb_class_new(mrb_state *mrb, struct RClass *super)
{
  struct RClass *c;

  if (super) {
    mrb_check_inheritable(mrb, super);
  }
  c = boot_defclass(mrb, super);
yui-knk's avatar
yui-knk committed
1538
  if (super) {
Masamitsu MURASE's avatar
Masamitsu MURASE committed
1539 1540
    MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super));
  }
mimaki's avatar
mimaki committed
1541 1542 1543 1544 1545 1546 1547 1548
  make_metaclass(mrb, c);

  return c;
}

/*!
 * Creates a new module.
 */
1549
MRB_API struct RClass*
mimaki's avatar
mimaki committed
1550 1551
mrb_module_new(mrb_state *mrb)
{
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1552
  struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class);
1553
  m->origin = m;
1554
  m->mt = kh_init(mt, mrb);
mimaki's avatar
mimaki committed
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572

  return m;
}

/*
 *  call-seq:
 *     obj.class    => class
 *
 *  Returns the class of <i>obj</i>, now preferred over
 *  <code>Object#type</code>, as an object's type in Ruby is only
 *  loosely tied to that object's class. This method must always be
 *  called with an explicit receiver, as <code>class</code> is also a
 *  reserved word in Ruby.
 *
 *     1.class      #=> Fixnum
 *     self.class   #=> Object
 */

1573
MRB_API struct RClass*
mimaki's avatar
mimaki committed
1574 1575
mrb_obj_class(mrb_state *mrb, mrb_value obj)
{
1576
  return mrb_class_real(mrb_class(mrb, obj));
mimaki's avatar
mimaki committed
1577 1578
}

1579
MRB_API void
mimaki's avatar
mimaki committed
1580 1581 1582
mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b)
{
  struct RProc *m = mrb_method_search(mrb, c, b);
roco's avatar
roco committed
1583

1584
  mrb_define_method_raw(mrb, c, a, m);
mimaki's avatar
mimaki committed
1585 1586 1587 1588 1589 1590 1591 1592
}

/*!
 * Defines an alias of a method.
 * \param klass  the class which the original method belongs to
 * \param name1  a new name for the method
 * \param name2  the original name of the method
 */
1593
MRB_API void
mimaki's avatar
mimaki committed
1594 1595
mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2)
{
1596
  mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2));
mimaki's avatar
mimaki committed
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
}

/*
 * call-seq:
 *   mod.to_s   -> string
 *
 * Return a string representing this module or class. For basic
 * classes and modules, this is the name. For singletons, we
 * show information on the thing we're attached to as well.
 */

static mrb_value
mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
{
1611 1612
  mrb_value str;

mimaki's avatar
mimaki committed
1613
  if (mrb_type(klass) == MRB_TT_SCLASS) {
1614
    mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__"));
mimaki's avatar
mimaki committed
1615

1616
    str = mrb_str_new_lit(mrb, "#<Class:");
1617

mimaki's avatar
mimaki committed
1618 1619 1620
    switch (mrb_type(v)) {
      case MRB_TT_CLASS:
      case MRB_TT_MODULE:
1621
      case MRB_TT_SCLASS:
1622
        mrb_str_append(mrb, str, mrb_inspect(mrb, v));
mimaki's avatar
mimaki committed
1623 1624
        break;
      default:
1625
        mrb_str_append(mrb, str, mrb_any_to_s(mrb, v));
mimaki's avatar
mimaki committed
1626 1627
        break;
    }
1628
    return mrb_str_cat_lit(mrb, str, ">");
mimaki's avatar
mimaki committed
1629 1630
  }
  else {
1631 1632 1633
    struct RClass *c;
    mrb_value path;

1634
    str = mrb_str_buf_new(mrb, 32);
1635 1636
    c = mrb_class_ptr(klass);
    path = mrb_class_path(mrb, c);
roco's avatar
roco committed
1637

1638
    if (mrb_nil_p(path)) {
mimaki's avatar
mimaki committed
1639
      switch (mrb_type(klass)) {
1640
        case MRB_TT_CLASS:
1641
          mrb_str_cat_lit(mrb, str, "#<Class:");
1642 1643 1644
          break;

        case MRB_TT_MODULE:
1645
          mrb_str_cat_lit(mrb, str, "#<Module:");
1646 1647 1648
          break;

        default:
1649
          /* Shouldn't be happened? */
1650
          mrb_str_cat_lit(mrb, str, "#<??????:");
1651
          break;
mimaki's avatar
mimaki committed
1652
      }
1653
      mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
1654
      return mrb_str_cat_lit(mrb, str, ">");
mimaki's avatar
mimaki committed
1655 1656
    }
    else {
1657
      return path;
mimaki's avatar
mimaki committed
1658 1659 1660 1661
    }
  }
}

1662
static mrb_value
mimaki's avatar
mimaki committed
1663 1664 1665
mrb_mod_alias(mrb_state *mrb, mrb_value mod)
{
  struct RClass *c = mrb_class_ptr(mod);
1666
  mrb_sym new_name, old_name;
mimaki's avatar
mimaki committed
1667

1668 1669
  mrb_get_args(mrb, "nn", &new_name, &old_name);
  mrb_alias_method(mrb, c, new_name, old_name);
mimaki's avatar
mimaki committed
1670 1671 1672
  return mrb_nil_value();
}

1673 1674
static void
undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
mimaki's avatar
mimaki committed
1675
{
1676
  if (!mrb_obj_respond_to(mrb, c, a)) {
1677
    mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c));
1678 1679
  }
  else {
1680
    mrb_define_method_raw(mrb, c, a, NULL);
1681
  }
mimaki's avatar
mimaki committed
1682 1683
}

1684
MRB_API void
1685 1686
mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
{
1687
  undef_method(mrb, c, mrb_intern_cstr(mrb, name));
1688 1689
}

1690
MRB_API void
1691 1692 1693 1694 1695
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);
}

1696
static mrb_value
mimaki's avatar
mimaki committed
1697 1698 1699
mrb_mod_undef(mrb_state *mrb, mrb_value mod)
{
  struct RClass *c = mrb_class_ptr(mod);
1700
  mrb_int argc;
mimaki's avatar
mimaki committed
1701 1702 1703 1704
  mrb_value *argv;

  mrb_get_args(mrb, "*", &argv, &argc);
  while (argc--) {
1705
    undef_method(mrb, c, mrb_symbol(*argv));
mimaki's avatar
mimaki committed
1706 1707 1708 1709 1710
    argv++;
  }
  return mrb_nil_value();
}

1711 1712 1713 1714
static mrb_value
mod_define_method(mrb_state *mrb, mrb_value self)
{
  struct RClass *c = mrb_class_ptr(self);
1715
  struct RProc *p;
1716 1717 1718 1719 1720
  mrb_sym mid;
  mrb_value blk;

  mrb_get_args(mrb, "n&", &mid, &blk);
  if (mrb_nil_p(blk)) {
1721
    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
1722
  }
1723 1724
  p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
  mrb_proc_copy(p, mrb_proc_ptr(blk));
1725
  p->flags |= MRB_PROC_STRICT;
1726
  mrb_define_method_raw(mrb, c, mid, p);
1727
  return mrb_symbol_value(mid);
1728 1729
}

1730 1731 1732 1733
static void
check_cv_name_str(mrb_state *mrb, mrb_value str)
{
  const char *s = RSTRING_PTR(str);
1734 1735
  mrb_int len = RSTRING_LEN(str);

1736
  if (len < 3 || !(s[0] == '@' && s[1] == '@')) {
1737
    mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str);
1738 1739 1740
  }
}

1741 1742 1743 1744 1745 1746
static void
check_cv_name_sym(mrb_state *mrb, mrb_sym id)
{
  check_cv_name_str(mrb, mrb_sym2str(mrb, id));
}

skandhas's avatar
skandhas committed
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
/* 15.2.2.4.16 */
/*
 *  call-seq:
 *     obj.class_variable_defined?(symbol)    -> true or false
 *
 *  Returns <code>true</code> if the given class variable is defined
 *  in <i>obj</i>.
 *
 *     class Fred
 *       @@foo = 99
 *     end
 *     Fred.class_variable_defined?(:@@foo)    #=> true
 *     Fred.class_variable_defined?(:@@bar)    #=> false
 */

static mrb_value
mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
{
1765
  mrb_sym id;
skandhas's avatar
skandhas committed
1766

1767
  mrb_get_args(mrb, "n", &id);
1768 1769
  check_cv_name_sym(mrb, id);
  return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
skandhas's avatar
skandhas committed
1770 1771
}

skandhas's avatar
skandhas committed
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
/* 15.2.2.4.17 */
/*
 *  call-seq:
 *     mod.class_variable_get(symbol)    -> obj
 *
 *  Returns the value of the given class variable (or throws a
 *  <code>NameError</code> exception). The <code>@@</code> part of the
 *  variable name should be included for regular class variables
 *
 *     class Fred
 *       @@foo = 99
 *     end
 *     Fred.class_variable_get(:@@foo)     #=> 99
 */

static mrb_value
mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod)
{
  mrb_sym id;

1792
  mrb_get_args(mrb, "n", &id);
1793
  check_cv_name_sym(mrb, id);
skandhas's avatar
skandhas committed
1794 1795 1796
  return mrb_cv_get(mrb, mod, id);
}

skandhas's avatar
skandhas committed
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
/* 15.2.2.4.18 */
/*
 *  call-seq:
 *     obj.class_variable_set(symbol, obj)    -> obj
 *
 *  Sets the class variable names by <i>symbol</i> to
 *  <i>object</i>.
 *
 *     class Fred
 *       @@foo = 99
 *       def foo
 *         @@foo
 *       end
 *     end
 *     Fred.class_variable_set(:@@foo, 101)     #=> 101
 *     Fred.new.foo                             #=> 101
 */

static mrb_value
mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod)
{
1818
  mrb_value value;
skandhas's avatar
skandhas committed
1819 1820
  mrb_sym id;

1821
  mrb_get_args(mrb, "no", &id, &value);
1822
  check_cv_name_sym(mrb, id);
skandhas's avatar
skandhas committed
1823 1824 1825 1826
  mrb_cv_set(mrb, mod, id, value);
  return value;
}

skandhas's avatar
skandhas committed
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849
/* 15.2.2.4.39 */
/*
 *  call-seq:
 *     remove_class_variable(sym)    -> obj
 *
 *  Removes the definition of the <i>sym</i>, returning that
 *  constant's value.
 *
 *     class Dummy
 *       @@var = 99
 *       puts @@var
 *       p class_variables
 *       remove_class_variable(:@@var)
 *       p class_variables
 *     end
 *
 *  <em>produces:</em>
 *
 *     99
 *     [:@@var]
 *     []
 */

1850
static mrb_value
skandhas's avatar
skandhas committed
1851 1852
mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
{
1853
  mrb_value val;
skandhas's avatar
skandhas committed
1854 1855
  mrb_sym id;

1856
  mrb_get_args(mrb, "n", &id);
1857
  check_cv_name_sym(mrb, id);
skandhas's avatar
skandhas committed
1858 1859 1860 1861

  val = mrb_iv_remove(mrb, mod, id);
  if (!mrb_undef_p(val)) return val;

yui-knk's avatar
yui-knk committed
1862
  if (mrb_cv_defined(mrb, mod, id)) {
1863 1864
    mrb_name_error(mrb, id, "cannot remove %S for %S",
                   mrb_sym2str(mrb, id), mod);
skandhas's avatar
skandhas committed
1865 1866
  }

1867 1868
  mrb_name_error(mrb, id, "class variable %S not defined for %S",
                 mrb_sym2str(mrb, id), mod);
skandhas's avatar
skandhas committed
1869 1870 1871 1872 1873

 /* not reached */
 return mrb_nil_value();
}

skandhas's avatar
skandhas committed
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
/* 15.2.2.4.34 */
/*
 *  call-seq:
 *     mod.method_defined?(symbol)    -> true or false
 *
 *  Returns +true+ if the named method is defined by
 *  _mod_ (or its included modules and, if _mod_ is a class,
 *  its ancestors). Public and protected methods are matched.
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       def method2()  end
 *     end
 *     class C < B
 *       include A
 *       def method3()  end
 *     end
 *
 *     A.method_defined? :method1    #=> true
 *     C.method_defined? "method1"   #=> true
 *     C.method_defined? "method2"   #=> true
 *     C.method_defined? "method3"   #=> true
 *     C.method_defined? "method4"   #=> false
 */

static mrb_value
mrb_mod_method_defined(mrb_state *mrb, mrb_value mod)
{
1904
  mrb_sym id;
skandhas's avatar
skandhas committed
1905

1906
  mrb_get_args(mrb, "n", &id);
1907
  return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id));
skandhas's avatar
skandhas committed
1908 1909
}

1910
static void
1911
remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
1912
{
1913
  struct RClass *c = mrb_class_ptr(mod);
1914 1915 1916 1917
  khash_t(mt) *h = c->mt;
  khiter_t k;

  if (h) {
1918
    k = kh_get(mt, mrb, h, mid);
1919
    if (k != kh_end(h)) {
1920
      kh_del(mt, mrb, h, k);
1921 1922 1923 1924
      return;
    }
  }

1925
  mrb_name_error(mrb, mid, "method '%S' not defined in %S",
1926
    mrb_sym2str(mrb, mid), mod);
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937
}

/* 15.2.2.4.41 */
/*
 *  call-seq:
 *     remove_method(symbol)   -> self
 *
 *  Removes the method identified by _symbol_ from the current
 *  class. For an example, see <code>Module.undef_method</code>.
 */

1938
static mrb_value
1939 1940
mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
{
1941
  mrb_int argc;
1942 1943 1944 1945
  mrb_value *argv;

  mrb_get_args(mrb, "*", &argv, &argc);
  while (argc--) {
1946
    remove_method(mrb, mod, mrb_symbol(*argv));
1947 1948 1949 1950 1951
    argv++;
  }
  return mod;
}

skandhas's avatar
skandhas committed
1952 1953


1954 1955 1956 1957 1958 1959 1960 1961
static void
check_const_name_str(mrb_state *mrb, mrb_value str)
{
  if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) {
    mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str);
  }
}

1962 1963 1964 1965 1966 1967
static void
check_const_name_sym(mrb_state *mrb, mrb_sym id)
{
  check_const_name_str(mrb, mrb_sym2str(mrb, id));
}

1968 1969 1970 1971 1972 1973 1974 1975 1976
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));
}

1977
static mrb_value
1978 1979
mrb_mod_const_defined(mrb_state *mrb, mrb_value mod)
{
1980
  mrb_sym id;
1981
  mrb_bool inherit = TRUE;
1982

1983
  mrb_get_args(mrb, "n|b", &id, &inherit);
1984 1985
  check_const_name_sym(mrb, id);
  return const_defined(mrb, mod, id, inherit);
1986 1987
}

1988
static mrb_value
1989 1990
mrb_mod_const_get(mrb_state *mrb, mrb_value mod)
{
1991
  mrb_sym id;
1992

1993
  mrb_get_args(mrb, "n", &id);
1994
  check_const_name_sym(mrb, id);
1995
  return mrb_const_get(mrb, mod, id);
1996 1997
}

1998
static mrb_value
1999 2000
mrb_mod_const_set(mrb_state *mrb, mrb_value mod)
{
2001 2002
  mrb_sym id;
  mrb_value value;
2003

2004
  mrb_get_args(mrb, "no", &id, &value);
2005
  check_const_name_sym(mrb, id);
2006
  mrb_const_set(mrb, mod, id, value);
2007 2008 2009
  return value;
}

2010
static mrb_value
2011 2012
mrb_mod_remove_const(mrb_state *mrb, mrb_value mod)
{
2013
  mrb_sym id;
2014 2015
  mrb_value val;

2016
  mrb_get_args(mrb, "n", &id);
2017
  check_const_name_sym(mrb, id);
2018
  val = mrb_iv_remove(mrb, mod, id);
2019
  if (mrb_undef_p(val)) {
2020
    mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id));
2021 2022 2023
  }
  return val;
}
mimaki's avatar
mimaki committed
2024

2025
static mrb_value
2026 2027 2028 2029 2030
mrb_mod_const_missing(mrb_state *mrb, mrb_value mod)
{
  mrb_sym sym;

  mrb_get_args(mrb, "n", &sym);
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040

  if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) {
    mrb_name_error(mrb, sym, "uninitialized constant %S::%S",
                   mod,
                   mrb_sym2str(mrb, sym));
  }
  else {
    mrb_name_error(mrb, sym, "uninitialized constant %S",
                   mrb_sym2str(mrb, sym));
  }
2041 2042 2043 2044
  /* not reached */
  return mrb_nil_value();
}

2045 2046 2047 2048
static mrb_value
mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
{
  mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented");
2049
  return mrb_nil_value();       /* not reached */
2050 2051
}

mimaki's avatar
mimaki committed
2052 2053 2054 2055
static mrb_value
mrb_mod_eqq(mrb_state *mrb, mrb_value mod)
{
  mrb_value obj;
2056
  mrb_bool eqq;
mimaki's avatar
mimaki committed
2057 2058

  mrb_get_args(mrb, "o", &obj);
2059 2060
  eqq = mrb_obj_is_kind_of(mrb, obj, mrb_class_ptr(mod));

2061
  return mrb_bool_value(eqq);
mimaki's avatar
mimaki committed
2062 2063
}

2064
MRB_API mrb_value
dreamedge's avatar
dreamedge committed
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
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);
Tatsuhiko Kubo's avatar
Tatsuhiko Kubo committed
2075

dreamedge's avatar
dreamedge committed
2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
  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;
}

mimaki's avatar
mimaki committed
2101 2102 2103
void
mrb_init_class(mrb_state *mrb)
{
roco's avatar
roco committed
2104 2105 2106 2107
  struct RClass *bob;           /* BasicObject */
  struct RClass *obj;           /* Object */
  struct RClass *mod;           /* Module */
  struct RClass *cls;           /* Class */
mimaki's avatar
mimaki committed
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121

  /* boot class hierarchy */
  bob = boot_defclass(mrb, 0);
  obj = boot_defclass(mrb, bob); mrb->object_class = obj;
  mod = boot_defclass(mrb, obj); mrb->module_class = mod;/* obj -> mod */
  cls = boot_defclass(mrb, mod); mrb->class_class = cls; /* obj -> cls */
  /* fix-up loose ends */
  bob->c = obj->c = mod->c = cls->c = cls;
  make_metaclass(mrb, bob);
  make_metaclass(mrb, obj);
  make_metaclass(mrb, mod);
  make_metaclass(mrb, cls);

  /* name basic classes */
2122
  mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob));
mimaki's avatar
mimaki committed
2123
  mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob));
MATSUMOTO Ryosuke's avatar
MATSUMOTO Ryosuke committed
2124 2125 2126
  mrb_define_const(mrb, obj, "Object",      mrb_obj_value(obj));
  mrb_define_const(mrb, obj, "Module",      mrb_obj_value(mod));
  mrb_define_const(mrb, obj, "Class",       mrb_obj_value(cls));
mimaki's avatar
mimaki committed
2127 2128

  /* name each classes */
2129
  name_class(mrb, bob, mrb_intern_lit(mrb, "BasicObject"));
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
2130 2131 2132
  name_class(mrb, obj, mrb_intern_lit(mrb, "Object"));           /* 15.2.1 */
  name_class(mrb, mod, mrb_intern_lit(mrb, "Module"));           /* 15.2.2 */
  name_class(mrb, cls, mrb_intern_lit(mrb, "Class"));            /* 15.2.3 */
mimaki's avatar
mimaki committed
2133

2134 2135 2136
  mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class);  /* 15.2.17 */
  MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC);

mimaki's avatar
mimaki committed
2137
  MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
2138 2139 2140
  mrb_define_method(mrb, bob, "initialize",              mrb_bob_init,             MRB_ARGS_NONE());
  mrb_define_method(mrb, bob, "!",                       mrb_bob_not,              MRB_ARGS_NONE());
  mrb_define_method(mrb, bob, "method_missing",          mrb_bob_missing,          MRB_ARGS_ANY());  /* 15.3.1.3.30 */
MATSUMOTO Ryosuke's avatar
MATSUMOTO Ryosuke committed
2141

2142
  mrb_define_class_method(mrb, cls, "new",               mrb_class_new_class,      MRB_ARGS_OPT(1));
2143
  mrb_define_method(mrb, cls, "superclass",              mrb_class_superclass,     MRB_ARGS_NONE()); /* 15.2.3.3.4 */
2144
  mrb_define_method(mrb, cls, "new",                     mrb_instance_new,         MRB_ARGS_ANY());  /* 15.2.3.3.3 */
2145
  mrb_define_method(mrb, cls, "initialize",              mrb_class_initialize,     MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */
2146
  mrb_define_method(mrb, cls, "inherited",               mrb_bob_init,             MRB_ARGS_REQ(1));
MATSUMOTO Ryosuke's avatar
MATSUMOTO Ryosuke committed
2147

2148
  MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE);
2149 2150 2151 2152 2153
  mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined,     MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */
  mrb_define_method(mrb, mod, "class_variable_get",      mrb_mod_cvar_get,         MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */
  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 */
Blaž Hrastnik's avatar
Blaž Hrastnik committed
2154 2155 2156
  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));
2157 2158 2159 2160 2161 2162
  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 */
  mrb_define_method(mrb, mod, "class_eval",              mrb_mod_module_eval,      MRB_ARGS_ANY());  /* 15.2.2.4.15 */
  mrb_define_method(mrb, mod, "included",                mrb_bob_init,             MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */
  mrb_define_method(mrb, mod, "included_modules",        mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
2163
  mrb_define_method(mrb, mod, "initialize",              mrb_mod_initialize,       MRB_ARGS_NONE()); /* 15.2.2.4.31 */
2164 2165 2166
  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 */
dreamedge's avatar
dreamedge committed
2167
  mrb_define_method(mrb, mod, "module_function",         mrb_mod_module_function,  MRB_ARGS_ANY());
2168 2169 2170
  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 */
2171 2172
  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 */
2173 2174
  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 */
2175 2176 2177 2178 2179
  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 */
2180
  mrb_define_method(mrb, mod, "const_defined?",          mrb_mod_const_defined,    MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */
2181 2182
  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 */
2183
  mrb_define_method(mrb, mod, "constants",               mrb_mod_constants,        MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
2184
  mrb_define_method(mrb, mod, "remove_const",            mrb_mod_remove_const,     MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */
2185
  mrb_define_method(mrb, mod, "const_missing",           mrb_mod_const_missing,    MRB_ARGS_REQ(1));
2186 2187 2188 2189
  mrb_define_method(mrb, mod, "define_method",           mod_define_method,        MRB_ARGS_REQ(1));
  mrb_define_method(mrb, mod, "class_variables",         mrb_mod_class_variables,  MRB_ARGS_NONE()); /* 15.2.2.4.19 */
  mrb_define_method(mrb, mod, "===",                     mrb_mod_eqq,              MRB_ARGS_REQ(1));
  mrb_define_class_method(mrb, mod, "constants",         mrb_mod_s_constants,      MRB_ARGS_ANY());  /* 15.2.2.3.1 */
MATSUMOTO Ryosuke's avatar
MATSUMOTO Ryosuke committed
2190

2191
  mrb_undef_method(mrb, cls, "append_features");
2192
  mrb_undef_method(mrb, cls, "extend_object");
mimaki's avatar
mimaki committed
2193
}