parse.y 162 KB
Newer Older
mimaki's avatar
mimaki committed
1 2
/*
** parse.y - mruby parser
fleuria's avatar
fleuria committed
3
**
mimaki's avatar
mimaki committed
4 5 6
** See Copyright Notice in mruby.h
*/

mimaki's avatar
mimaki committed
7 8
%{
#undef PARSER_DEBUG
9 10 11
#ifdef PARSER_DEBUG
# define YYDEBUG 1
#endif
mimaki's avatar
mimaki committed
12
#define YYERROR_VERBOSE 1
13 14 15 16 17 18
/*
 * 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))
mimaki's avatar
mimaki committed
19 20
#define YYSTACK_USE_ALLOCA 0

21 22 23 24
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
25 26 27 28 29
#include <mruby.h>
#include <mruby/compile.h>
#include <mruby/proc.h>
#include <mruby/error.h>
#include <mruby/throw.h>
30 31
#include "node.h"

mimaki's avatar
mimaki committed
32 33 34 35
#define YYLEX_PARAM p

typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
36
typedef struct mrb_parser_heredoc_info parser_heredoc_info;
mimaki's avatar
mimaki committed
37

cremno's avatar
cremno committed
38
static int yyparse(parser_state *p);
mimaki's avatar
mimaki committed
39 40 41 42 43
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);
44
static void void_expr_error(parser_state *p, node *n);
45
static void tokadd(parser_state *p, int32_t c);
mimaki's avatar
mimaki committed
46

cremno's avatar
cremno committed
47
#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
mimaki's avatar
mimaki committed
48 49 50

typedef unsigned int stack_type;

51 52 53 54 55 56 57 58 59 60 61 62 63 64
#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)
mimaki's avatar
mimaki committed
65

66
#define SET_LINENO(c,n) ((c)->lineno = (n))
67 68 69 70 71 72
#define NODE_LINENO(c,n) do {\
  if (n) {\
     (c)->filename_index = (n)->filename_index;\
     (c)->lineno = (n)->lineno;\
  }\
} while (0)
h2so5's avatar
h2so5 committed
73

74 75
#define sym(x) ((mrb_sym)(intptr_t)(x))
#define nsym(x) ((node*)(intptr_t)(x))
76 77
#define nint(x) ((node*)(intptr_t)(x))
#define intn(x) ((int)(intptr_t)(x))
78

79
static inline mrb_sym
80
intern_cstr_gen(parser_state *p, const char *s)
mimaki's avatar
mimaki committed
81
{
82
  return mrb_intern_cstr(p->mrb, s);
mimaki's avatar
mimaki committed
83
}
84
#define intern_cstr(s) intern_cstr_gen(p,(s))
mimaki's avatar
mimaki committed
85

86
static inline mrb_sym
87
intern_gen(parser_state *p, const char *s, size_t len)
88
{
89
  return mrb_intern(p->mrb, s, len);
90
}
91
#define intern(s,len) intern_gen(p,(s),(len))
92

93 94 95
static inline mrb_sym
intern_gen_c(parser_state *p, const char c)
{
96
  return mrb_intern(p->mrb, &c, 1);
97 98 99
}
#define intern_c(c) intern_gen_c(p,(c))

mimaki's avatar
mimaki committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113
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) {
take_cheeze's avatar
take_cheeze committed
114
    MRB_THROW(p->jmp);
mimaki's avatar
mimaki committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128
  }
  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 {
Max Anselm's avatar
Max Anselm committed
129
    c = (node *)parser_palloc(p, sizeof(mrb_ast_node));
mimaki's avatar
mimaki committed
130 131 132 133
  }

  c->car = car;
  c->cdr = cdr;
134
  c->lineno = p->lineno;
135
  c->filename_index = p->current_filename_index;
mimaki's avatar
mimaki committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  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)
{
Max Anselm's avatar
Max Anselm committed
202
  char *b = (char *)parser_palloc(p, len+1);
mimaki's avatar
mimaki committed
203 204 205 206 207

  memcpy(b, s, len);
  b[len] = '\0';
  return b;
}
208
#undef strndup
mimaki's avatar
mimaki committed
209 210 211 212 213 214 215 216 217 218
#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)

219
/* xxx ----------------------------- */
mimaki's avatar
mimaki committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

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)
{
Carson McDonald's avatar
Carson McDonald committed
245 246 247
  if (p->locals) {
    p->locals = p->locals->cdr;
  }
mimaki's avatar
mimaki committed
248 249
}

250
static mrb_bool
mimaki's avatar
mimaki committed
251 252 253 254 255 256 257
local_var_p(parser_state *p, mrb_sym sym)
{
  node *l = p->locals;

  while (l) {
    node *n = l->car;
    while (n) {
258
      if (sym(n->car) == sym) return TRUE;
mimaki's avatar
mimaki committed
259 260 261 262
      n = n->cdr;
    }
    l = l->cdr;
  }
263
  return FALSE;
mimaki's avatar
mimaki committed
264 265 266 267 268
}

static void
local_add_f(parser_state *p, mrb_sym sym)
{
Carson McDonald's avatar
Carson McDonald committed
269 270 271
  if (p->locals) {
    p->locals->car = push(p->locals->car, nsym(sym));
  }
mimaki's avatar
mimaki committed
272 273 274 275 276 277 278 279 280 281
}

static void
local_add(parser_state *p, mrb_sym sym)
{
  if (!local_var_p(p, sym)) {
    local_add_f(p, sym);
  }
}

cremno's avatar
cremno committed
282 283 284 285 286 287
static node*
locals_node(parser_state *p)
{
  return p->locals ? p->locals->car : NULL;
}

288
/* (:scope (vars..) (prog...)) */
mimaki's avatar
mimaki committed
289 290 291
static node*
new_scope(parser_state *p, node *body)
{
cremno's avatar
cremno committed
292
  return cons((node*)NODE_SCOPE, cons(locals_node(p), body));
mimaki's avatar
mimaki committed
293 294
}

295
/* (:begin prog...) */
mimaki's avatar
mimaki committed
296 297 298
static node*
new_begin(parser_state *p, node *body)
{
299
  if (body) {
mimaki's avatar
mimaki committed
300
    return list2((node*)NODE_BEGIN, body);
301
  }
mimaki's avatar
mimaki committed
302 303 304 305 306
  return cons((node*)NODE_BEGIN, 0);
}

#define newline_node(n) (n)

307
/* (:rescue body rescue else) */
mimaki's avatar
mimaki committed
308 309 310 311 312 313
static node*
new_rescue(parser_state *p, node *body, node *resq, node *els)
{
  return list4((node*)NODE_RESCUE, body, resq, els);
}

314 315 316 317 318 319
static node*
new_mod_rescue(parser_state *p, node *body, node *resq)
{
  return new_rescue(p, body, list1(list3(0, 0, resq)), 0);
}

320
/* (:ensure body ensure) */
mimaki's avatar
mimaki committed
321 322 323 324 325 326
static node*
new_ensure(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_ENSURE, cons(a, cons(0, b)));
}

327
/* (:nil) */
mimaki's avatar
mimaki committed
328 329 330 331 332 333
static node*
new_nil(parser_state *p)
{
  return list1((node*)NODE_NIL);
}

334
/* (:true) */
mimaki's avatar
mimaki committed
335 336 337 338 339 340
static node*
new_true(parser_state *p)
{
  return list1((node*)NODE_TRUE);
}

341
/* (:false) */
mimaki's avatar
mimaki committed
342 343 344 345 346 347
static node*
new_false(parser_state *p)
{
  return list1((node*)NODE_FALSE);
}

348
/* (:alias new old) */
mimaki's avatar
mimaki committed
349 350 351
static node*
new_alias(parser_state *p, mrb_sym a, mrb_sym b)
{
352
  return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b)));
mimaki's avatar
mimaki committed
353 354
}

355
/* (:if cond then else) */
mimaki's avatar
mimaki committed
356 357 358 359 360 361
static node*
new_if(parser_state *p, node *a, node *b, node *c)
{
  return list4((node*)NODE_IF, a, b, c);
}

362
/* (:unless cond then else) */
mimaki's avatar
mimaki committed
363 364 365 366 367 368
static node*
new_unless(parser_state *p, node *a, node *b, node *c)
{
  return list4((node*)NODE_IF, a, c, b);
}

369
/* (:while cond body) */
mimaki's avatar
mimaki committed
370 371 372 373 374 375
static node*
new_while(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_WHILE, cons(a, b));
}

376
/* (:until cond body) */
mimaki's avatar
mimaki committed
377 378 379 380 381 382
static node*
new_until(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_UNTIL, cons(a, b));
}

383
/* (:for var obj body) */
mimaki's avatar
mimaki committed
384 385 386 387 388 389
static node*
new_for(parser_state *p, node *v, node *o, node *b)
{
  return list4((node*)NODE_FOR, v, o, b);
}

390
/* (:case a ((when ...) body) ((when...) body)) */
mimaki's avatar
mimaki committed
391 392 393 394 395 396 397 398 399 400 401 402 403
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;
}

404
/* (:postexe a) */
mimaki's avatar
mimaki committed
405 406 407 408 409 410
static node*
new_postexe(parser_state *p, node *a)
{
  return cons((node*)NODE_POSTEXE, a);
}

411
/* (:self) */
mimaki's avatar
mimaki committed
412 413 414 415 416 417
static node*
new_self(parser_state *p)
{
  return list1((node*)NODE_SELF);
}

418
/* (:call a b c) */
mimaki's avatar
mimaki committed
419
static node*
420
new_call(parser_state *p, node *a, mrb_sym b, node *c, int pass)
mimaki's avatar
mimaki committed
421
{
422
  node *n = list4(nint(pass?NODE_CALL:NODE_SCALL), a, nsym(b), c);
423 424
  NODE_LINENO(n, a);
  return n;
mimaki's avatar
mimaki committed
425 426
}

427
/* (:fcall self mid args) */
mimaki's avatar
mimaki committed
428 429 430
static node*
new_fcall(parser_state *p, mrb_sym b, node *c)
{
431 432 433 434 435
  node *n = new_self(p);
  NODE_LINENO(n, c);
  n = list4((node*)NODE_FCALL, n, nsym(b), c);
  NODE_LINENO(n, c);
  return n;
mimaki's avatar
mimaki committed
436 437
}

438
/* (:super . c) */
mimaki's avatar
mimaki committed
439 440 441 442 443 444
static node*
new_super(parser_state *p, node *c)
{
  return cons((node*)NODE_SUPER, c);
}

445
/* (:zsuper) */
mimaki's avatar
mimaki committed
446 447 448 449 450 451
static node*
new_zsuper(parser_state *p)
{
  return list1((node*)NODE_ZSUPER);
}

452
/* (:yield . c) */
mimaki's avatar
mimaki committed
453 454 455 456 457 458 459 460 461 462 463 464
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);
}

465
/* (:return . c) */
mimaki's avatar
mimaki committed
466 467 468 469 470 471
static node*
new_return(parser_state *p, node *c)
{
  return cons((node*)NODE_RETURN, c);
}

472
/* (:break . c) */
mimaki's avatar
mimaki committed
473 474 475 476 477 478
static node*
new_break(parser_state *p, node *c)
{
  return cons((node*)NODE_BREAK, c);
}

479
/* (:next . c) */
mimaki's avatar
mimaki committed
480 481 482 483 484 485
static node*
new_next(parser_state *p, node *c)
{
  return cons((node*)NODE_NEXT, c);
}

486
/* (:redo) */
mimaki's avatar
mimaki committed
487 488 489 490 491 492
static node*
new_redo(parser_state *p)
{
  return list1((node*)NODE_REDO);
}

493
/* (:retry) */
mimaki's avatar
mimaki committed
494 495 496 497 498 499
static node*
new_retry(parser_state *p)
{
  return list1((node*)NODE_RETRY);
}

500
/* (:dot2 a b) */
mimaki's avatar
mimaki committed
501 502 503 504 505 506
static node*
new_dot2(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_DOT2, cons(a, b));
}

507
/* (:dot3 a b) */
mimaki's avatar
mimaki committed
508 509 510 511 512 513
static node*
new_dot3(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_DOT3, cons(a, b));
}

514
/* (:colon2 b c) */
mimaki's avatar
mimaki committed
515 516 517
static node*
new_colon2(parser_state *p, node *b, mrb_sym c)
{
518
  return cons((node*)NODE_COLON2, cons(b, nsym(c)));
mimaki's avatar
mimaki committed
519 520
}

521
/* (:colon3 . c) */
mimaki's avatar
mimaki committed
522 523 524
static node*
new_colon3(parser_state *p, mrb_sym c)
{
525
  return cons((node*)NODE_COLON3, nsym(c));
mimaki's avatar
mimaki committed
526 527
}

528
/* (:and a b) */
mimaki's avatar
mimaki committed
529 530 531 532 533 534
static node*
new_and(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_AND, cons(a, b));
}

535
/* (:or a b) */
mimaki's avatar
mimaki committed
536 537 538 539 540 541
static node*
new_or(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_OR, cons(a, b));
}

542
/* (:array a...) */
mimaki's avatar
mimaki committed
543 544 545 546 547 548
static node*
new_array(parser_state *p, node *a)
{
  return cons((node*)NODE_ARRAY, a);
}

549
/* (:splat . a) */
mimaki's avatar
mimaki committed
550 551 552 553 554 555
static node*
new_splat(parser_state *p, node *a)
{
  return cons((node*)NODE_SPLAT, a);
}

556
/* (:hash (k . v) (k . v)...) */
mimaki's avatar
mimaki committed
557 558 559 560 561 562
static node*
new_hash(parser_state *p, node *a)
{
  return cons((node*)NODE_HASH, a);
}

563
/* (:sym . a) */
mimaki's avatar
mimaki committed
564 565 566
static node*
new_sym(parser_state *p, mrb_sym sym)
{
567
  return cons((node*)NODE_SYM, nsym(sym));
mimaki's avatar
mimaki committed
568 569
}

570 571 572 573 574 575
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;

576
  return mrb_intern(p->mrb, s, len);
577 578
}

579
/* (:lvar . a) */
mimaki's avatar
mimaki committed
580 581 582
static node*
new_lvar(parser_state *p, mrb_sym sym)
{
583
  return cons((node*)NODE_LVAR, nsym(sym));
mimaki's avatar
mimaki committed
584 585
}

586
/* (:gvar . a) */
mimaki's avatar
mimaki committed
587 588 589
static node*
new_gvar(parser_state *p, mrb_sym sym)
{
590
  return cons((node*)NODE_GVAR, nsym(sym));
mimaki's avatar
mimaki committed
591 592
}

593
/* (:ivar . a) */
mimaki's avatar
mimaki committed
594 595 596
static node*
new_ivar(parser_state *p, mrb_sym sym)
{
597
  return cons((node*)NODE_IVAR, nsym(sym));
mimaki's avatar
mimaki committed
598 599
}

600
/* (:cvar . a) */
mimaki's avatar
mimaki committed
601 602 603
static node*
new_cvar(parser_state *p, mrb_sym sym)
{
604
  return cons((node*)NODE_CVAR, nsym(sym));
mimaki's avatar
mimaki committed
605 606
}

607
/* (:const . a) */
mimaki's avatar
mimaki committed
608 609 610
static node*
new_const(parser_state *p, mrb_sym sym)
{
611
  return cons((node*)NODE_CONST, nsym(sym));
mimaki's avatar
mimaki committed
612 613
}

614
/* (:undef a...) */
mimaki's avatar
mimaki committed
615 616 617
static node*
new_undef(parser_state *p, mrb_sym sym)
{
618
  return list2((node*)NODE_UNDEF, nsym(sym));
mimaki's avatar
mimaki committed
619 620
}

621
/* (:class class super body) */
mimaki's avatar
mimaki committed
622 623 624
static node*
new_class(parser_state *p, node *c, node *s, node *b)
{
cremno's avatar
cremno committed
625
  return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b));
mimaki's avatar
mimaki committed
626 627
}

628
/* (:sclass obj body) */
mimaki's avatar
mimaki committed
629 630 631
static node*
new_sclass(parser_state *p, node *o, node *b)
{
cremno's avatar
cremno committed
632
  return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b));
mimaki's avatar
mimaki committed
633 634
}

635
/* (:module module body) */
mimaki's avatar
mimaki committed
636 637 638
static node*
new_module(parser_state *p, node *m, node *b)
{
cremno's avatar
cremno committed
639
  return list3((node*)NODE_MODULE, m, cons(locals_node(p), b));
mimaki's avatar
mimaki committed
640 641
}

642
/* (:def m lv (arg . body)) */
mimaki's avatar
mimaki committed
643 644 645
static node*
new_def(parser_state *p, mrb_sym m, node *a, node *b)
{
cremno's avatar
cremno committed
646
  return list5((node*)NODE_DEF, nsym(m), locals_node(p), a, b);
mimaki's avatar
mimaki committed
647 648
}

649
/* (:sdef obj m lv (arg . body)) */
mimaki's avatar
mimaki committed
650 651 652
static node*
new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b)
{
cremno's avatar
cremno committed
653
  return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b);
mimaki's avatar
mimaki committed
654 655
}

656
/* (:arg . sym) */
mimaki's avatar
mimaki committed
657 658 659
static node*
new_arg(parser_state *p, mrb_sym sym)
{
660
  return cons((node*)NODE_ARG, nsym(sym));
mimaki's avatar
mimaki committed
661 662
}

663 664 665 666 667 668
/* (m o r m2 b) */
/* m: (a b c) */
/* o: ((a . e1) (b . e2)) */
/* r: a */
/* m2: (a b c) */
/* b: a */
mimaki's avatar
mimaki committed
669 670 671 672 673
static node*
new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
{
  node *n;

674 675
  n = cons(m2, nsym(blk));
  n = cons(nsym(rest), n);
mimaki's avatar
mimaki committed
676 677 678 679
  n = cons(opt, n);
  return cons(m, n);
}

680
/* (:block_arg . a) */
mimaki's avatar
mimaki committed
681 682 683 684 685 686
static node*
new_block_arg(parser_state *p, node *a)
{
  return cons((node*)NODE_BLOCK_ARG, a);
}

687
/* (:block arg body) */
mimaki's avatar
mimaki committed
688 689 690
static node*
new_block(parser_state *p, node *a, node *b)
{
cremno's avatar
cremno committed
691
  return list4((node*)NODE_BLOCK, locals_node(p), a, b);
mimaki's avatar
mimaki committed
692 693
}

694
/* (:lambda arg body) */
mimaki's avatar
mimaki committed
695 696 697
static node*
new_lambda(parser_state *p, node *a, node *b)
{
cremno's avatar
cremno committed
698
  return list4((node*)NODE_LAMBDA, locals_node(p), a, b);
mimaki's avatar
mimaki committed
699 700
}

701
/* (:asgn lhs rhs) */
mimaki's avatar
mimaki committed
702 703 704 705 706 707
static node*
new_asgn(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_ASGN, cons(a, b));
}

708
/* (:masgn mlhs=(pre rest post)  mrhs) */
mimaki's avatar
mimaki committed
709 710 711 712 713 714
static node*
new_masgn(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_MASGN, cons(a, b));
}

715
/* (:asgn lhs rhs) */
mimaki's avatar
mimaki committed
716 717 718
static node*
new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
{
719
  return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
mimaki's avatar
mimaki committed
720 721
}

722
/* (:int . i) */
mimaki's avatar
mimaki committed
723 724 725
static node*
new_int(parser_state *p, const char *s, int base)
{
726
  return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
mimaki's avatar
mimaki committed
727 728
}

729
/* (:float . i) */
mimaki's avatar
mimaki committed
730 731 732 733 734 735
static node*
new_float(parser_state *p, const char *s)
{
  return cons((node*)NODE_FLOAT, (node*)strdup(s));
}

736
/* (:str . (s . len)) */
mimaki's avatar
mimaki committed
737
static node*
738
new_str(parser_state *p, const char *s, int len)
mimaki's avatar
mimaki committed
739
{
740
  return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len)));
mimaki's avatar
mimaki committed
741 742
}

743
/* (:dstr . a) */
mimaki's avatar
mimaki committed
744 745 746 747 748 749
static node*
new_dstr(parser_state *p, node *a)
{
  return cons((node*)NODE_DSTR, a);
}

750
/* (:str . (s . len)) */
mattn's avatar
mattn committed
751 752 753
static node*
new_xstr(parser_state *p, const char *s, int len)
{
754
  return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), nint(len)));
mattn's avatar
mattn committed
755 756
}

757
/* (:xstr . a) */
mattn's avatar
mattn committed
758 759 760 761 762 763
static node*
new_dxstr(parser_state *p, node *a)
{
  return cons((node*)NODE_DXSTR, a);
}

764
/* (:dsym . a) */
765 766 767 768 769 770
static node*
new_dsym(parser_state *p, node *a)
{
  return cons((node*)NODE_DSYM, new_dstr(p, a));
}

771
/* (:regx . (s . (opt . enc))) */
mattn's avatar
mattn committed
772
static node*
773
new_regx(parser_state *p, const char *p1, const char* p2, const char* p3)
mattn's avatar
mattn committed
774
{
775
  return cons((node*)NODE_REGX, cons((node*)p1, cons((node*)p2, (node*)p3)));
mattn's avatar
mattn committed
776 777
}

778
/* (:dregx . (a . b)) */
779 780 781 782 783 784
static node*
new_dregx(parser_state *p, node *a, node *b)
{
  return cons((node*)NODE_DREGX, cons(a, b));
}

785
/* (:backref . n) */
mimaki's avatar
mimaki committed
786 787 788
static node*
new_back_ref(parser_state *p, int n)
{
789
  return cons((node*)NODE_BACK_REF, nint(n));
mimaki's avatar
mimaki committed
790 791
}

792
/* (:nthref . n) */
mimaki's avatar
mimaki committed
793 794 795
static node*
new_nth_ref(parser_state *p, int n)
{
796
  return cons((node*)NODE_NTH_REF, nint(n));
mimaki's avatar
mimaki committed
797 798
}

799
/* (:heredoc . a) */
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
800 801 802
static node*
new_heredoc(parser_state *p)
{
803
  parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info));
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
804 805 806
  return cons((node*)NODE_HEREDOC, (node*)inf);
}

mimaki's avatar
mimaki committed
807 808 809 810 811
static void
new_bv(parser_state *p, mrb_sym id)
{
}

812 813 814 815 816 817
static node*
new_literal_delim(parser_state *p)
{
  return cons((node*)NODE_LITERAL_DELIM, 0);
}

818
/* (:words . a) */
819 820 821 822 823 824
static node*
new_words(parser_state *p, node *a)
{
  return cons((node*)NODE_WORDS, a);
}

825
/* (:symbols . a) */
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
826 827 828 829 830 831
static node*
new_symbols(parser_state *p, node *a)
{
  return cons((node*)NODE_SYMBOLS, a);
}

832
/* xxx ----------------------------- */
mimaki's avatar
mimaki committed
833

834
/* (:call a op) */
mimaki's avatar
mimaki committed
835
static node*
836
call_uni_op(parser_state *p, node *recv, const char *m)
mimaki's avatar
mimaki committed
837
{
838
  return new_call(p, recv, intern_cstr(m), 0, 1);
mimaki's avatar
mimaki committed
839 840
}

841
/* (:call a op b) */
mimaki's avatar
mimaki committed
842
static node*
843
call_bin_op(parser_state *p, node *recv, const char *m, node *arg1)
mimaki's avatar
mimaki committed
844
{
845
  return new_call(p, recv, intern_cstr(m), list1(list1(arg1)), 1);
mimaki's avatar
mimaki committed
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
}

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)
{
862
  node *n;
mimaki's avatar
mimaki committed
863

864
  switch ((enum node_type)intn(a->car)) {
865 866
  case NODE_SUPER:
  case NODE_ZSUPER:
867 868 869 870
    if (!a->cdr) a->cdr = cons(0, b);
    else {
      args_with_block(p, a->cdr, b);
    }
871 872 873
    break;
  case NODE_CALL:
  case NODE_FCALL:
874
  case NODE_SCALL:
875 876 877 878 879
    n = a->cdr->cdr->cdr;
    if (!n->car) n->car = cons(0, b);
    else {
      args_with_block(p, n->car, b);
    }
880 881 882
    break;
  default:
    break;
mimaki's avatar
mimaki committed
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
  }
}

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");
903
    return NULL;
mimaki's avatar
mimaki committed
904 905 906 907 908 909 910 911
  }
  if (!n->car->cdr) return n->car->car;
  return new_array(p, n->car);
}

static void
assignable(parser_state *p, node *lhs)
{
912
  if (intn(lhs->car) == NODE_LVAR) {
913
    local_add(p, sym(lhs->cdr));
mimaki's avatar
mimaki committed
914 915 916 917 918 919 920 921
  }
}

static node*
var_reference(parser_state *p, node *lhs)
{
  node *n;

922
  if (intn(lhs->car) == NODE_LVAR) {
923 924
    if (!local_var_p(p, sym(lhs->cdr))) {
      n = new_fcall(p, sym(lhs->cdr), 0);
mimaki's avatar
mimaki committed
925 926 927 928
      cons_free(lhs);
      return n;
    }
  }
929

mimaki's avatar
mimaki committed
930 931 932
  return lhs;
}

933
typedef enum mrb_string_type  string_type;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
934 935

static node*
936 937
new_strterm(parser_state *p, string_type type, int term, int paren)
{
938
  return cons(nint(type), cons((node*)0, cons(nint(paren), nint(term))));
939 940 941 942 943 944 945 946 947 948 949
}

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

cremno's avatar
cremno committed
950
static parser_heredoc_info *
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
951 952 953 954 955
parsing_heredoc_inf(parser_state *p)
{
  node *nd = p->parsing_heredoc;
  if (nd == NULL)
    return NULL;
fleuria's avatar
fleuria committed
956
  /* mrb_assert(nd->car->car == NODE_HEREDOC); */
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
957 958 959
  return (parser_heredoc_info*)nd->car->cdr;
}

FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
960 961 962 963 964 965 966 967 968 969 970 971 972
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)
h2so5's avatar
h2so5 committed
973
        n = n->cdr;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
974
      n->cdr = p->parsing_heredoc;
975 976
    }
    else {
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
977 978
      p->all_heredocs = p->parsing_heredoc;
    }
979 980
  }
  else {
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
981 982 983 984 985 986 987 988 989 990
    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;
991 992
    }
    else {
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
993
      while (n->cdr != p->parsing_heredoc) {
h2so5's avatar
h2so5 committed
994 995
        n = n->cdr;
        mrb_assert(n != NULL);
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
996 997 998 999 1000 1001 1002 1003 1004
      }
      m->cdr = n->cdr;
      n->cdr = p->heredocs_from_nextline;
      p->parsing_heredoc = p->heredocs_from_nextline;
    }
  }
  p->heredocs_from_nextline = NULL;
}

FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1005 1006 1007 1008 1009 1010 1011
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;
1012
    end_strterm(p);
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1013 1014
    p->lex_strterm = p->lex_strterm_before_heredoc;
    p->lex_strterm_before_heredoc = NULL;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1015
    p->heredoc_end_now = TRUE;
1016 1017
  }
  else {
1018
    /* next heredoc */
1019
    p->lex_strterm->car = nint(parsing_heredoc_inf(p)->type);
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1020 1021
  }
}
1022
#define is_strterm_type(p,str_func) (intn((p)->lex_strterm->car) & (str_func))
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1023

1024
/* xxx ----------------------------- */
mimaki's avatar
mimaki committed
1025 1026 1027

%}

Cremno's avatar
Cremno committed
1028
%pure-parser
mimaki's avatar
mimaki committed
1029 1030 1031 1032
%parse-param {parser_state *p}
%lex-param {parser_state *p}

%union {
1033
    node *nd;
mimaki's avatar
mimaki committed
1034 1035
    mrb_sym id;
    int num;
1036
    stack_type stack;
mimaki's avatar
mimaki committed
1037 1038 1039
    const struct vtable *vars;
}

1040
%token <num>
h2so5's avatar
h2so5 committed
1041 1042 1043 1044
        keyword_class
        keyword_module
        keyword_def
        keyword_begin
1045 1046 1047 1048 1049 1050 1051 1052
        keyword_if
        keyword_unless
        keyword_while
        keyword_until
        keyword_for

%token
        keyword_undef
h2so5's avatar
h2so5 committed
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
        keyword_rescue
        keyword_ensure
        keyword_end
        keyword_then
        keyword_elsif
        keyword_else
        keyword_case
        keyword_when
        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__
mimaki's avatar
mimaki committed
1091

kano4's avatar
kano4 committed
1092
%token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
mattn's avatar
mattn committed
1093
%token <nd>  tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
1094
%token <nd>  tSTRING tSTRING_PART tSTRING_MID tLABEL_END
kano4's avatar
kano4 committed
1095 1096
%token <nd>  tNTH_REF tBACK_REF
%token <num> tREGEXP_END
mimaki's avatar
mimaki committed
1097

mattn's avatar
mattn committed
1098
%type <nd> singleton string string_rep string_interp xstring regexp
1099
%type <nd> literal numeric cpath symbol
1100 1101
%type <nd> top_compstmt top_stmts top_stmt
%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
1102
%type <nd> expr_value arg_rhs primary_value
1103 1104 1105 1106
%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
1107
%type <nd> command_asgn command_rhs mrhs superclass block_call block_command
1108 1109 1110 1111 1112
%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
1113
%type <nd> brace_block cmd_brace_block do_block lhs none f_bad_arg
1114
%type <nd> mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner
1115
%type <id> fsym sym basic_symbol operation operation2 operation3
1116
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1117
%type <nd> heredoc words symbols
1118
%type <num> call_op call_op2     /* 0:'&.', 1:'.', 2:'::' */
mimaki's avatar
mimaki committed
1119

kano4's avatar
kano4 committed
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
%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            /* -> */
1147
%token tANDDOT            /* &. */
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1148
%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG
mattn's avatar
mattn committed
1149
%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG
kano4's avatar
kano4 committed
1150
%token <nd> tHEREDOC_BEG  /* <<, <<- */
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
1151 1152
%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM
%token <nd> tHD_STRING_PART tHD_STRING_MID
mimaki's avatar
mimaki committed
1153 1154

/*
h2so5's avatar
h2so5 committed
1155
 * precedence table
mimaki's avatar
mimaki committed
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
 */

%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

%token tLAST_TOKEN

%%
h2so5's avatar
h2so5 committed
1184 1185 1186 1187 1188 1189 1190
program         :   {
                      p->lstate = EXPR_BEG;
                      if (!p->locals) p->locals = cons(0,0);
                    }
                  top_compstmt
                    {
                      p->tree = new_scope(p, $2);
1191
                      NODE_LINENO(p->tree, $2);
h2so5's avatar
h2so5 committed
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
                    }
                ;

top_compstmt    : top_stmts opt_terms
                    {
                      $$ = $1;
                    }
                ;

top_stmts       : none
                    {
                      $$ = new_begin(p, 0);
                    }
                | top_stmt
                    {
                      $$ = new_begin(p, $1);
1208
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
                    }
                | 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);
1240
                        NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
                      }
                      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);
1273
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1274 1275 1276
                    }
                | stmts terms stmt
                    {
1277
                      $$ = push($1, newline_node($3));
h2so5's avatar
h2so5 committed
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
                    }
                | 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
                    {
1295
                      $$ = new_if(p, cond($3), $1, 0);
h2so5's avatar
h2so5 committed
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
                    }
                | 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
                    {
1311
                      $$ = new_mod_rescue(p, $1, $3);
h2so5's avatar
h2so5 committed
1312 1313 1314
                    }
                | keyword_END '{' compstmt '}'
                    {
HAYASHI Kentaro's avatar
HAYASHI Kentaro committed
1315
                      yyerror(p, "END not supported");
h2so5's avatar
h2so5 committed
1316 1317 1318 1319 1320 1321 1322
                      $$ = new_postexe(p, $3);
                    }
                | command_asgn
                | mlhs '=' command_call
                    {
                      $$ = new_masgn(p, $1, $3);
                    }
1323 1324 1325 1326
                | lhs '=' mrhs
                    {
                      $$ = new_asgn(p, $1, new_array(p, $3));
                    }
1327
                | mlhs '=' arg
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
                    {
                      $$ = new_masgn(p, $1, $3);
                    }
                | mlhs '=' mrhs
                    {
                      $$ = new_masgn(p, $1, new_array(p, $3));
                    }
                | expr
                ;

command_asgn    : lhs '=' command_rhs
                    {
                      $$ = new_asgn(p, $1, $3);
                    }
1342
                | var_lhs tOP_ASGN command_rhs
h2so5's avatar
h2so5 committed
1343 1344 1345
                    {
                      $$ = new_op_asgn(p, $1, $2, $3);
                    }
1346
                | primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs
h2so5's avatar
h2so5 committed
1347
                    {
1348
                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
h2so5's avatar
h2so5 committed
1349
                    }
1350
                | primary_value call_op tIDENTIFIER tOP_ASGN command_rhs
h2so5's avatar
h2so5 committed
1351
                    {
1352
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5);
h2so5's avatar
h2so5 committed
1353
                    }
1354
                | primary_value call_op tCONSTANT tOP_ASGN command_rhs
h2so5's avatar
h2so5 committed
1355
                    {
1356
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5);
h2so5's avatar
h2so5 committed
1357 1358 1359 1360 1361 1362
                    }
                | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call
                    {
                      yyerror(p, "constant re-assignment");
                      $$ = 0;
                    }
1363
                | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs
h2so5's avatar
h2so5 committed
1364
                    {
1365
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, tCOLON2), $4, $5);
h2so5's avatar
h2so5 committed
1366
                    }
1367
                | backref tOP_ASGN command_rhs
1368 1369 1370 1371
                    {
                      backref_error(p, $1);
                      $$ = new_begin(p, 0);
                    }
1372 1373 1374 1375
		;

command_rhs     : command_call   %prec tOP_ASGN
                | command_call modifier_rescue stmt
h2so5's avatar
h2so5 committed
1376
                    {
1377
                      $$ = new_mod_rescue(p, $1, $3);
h2so5's avatar
h2so5 committed
1378
                    }
1379
                | command_asgn
h2so5's avatar
h2so5 committed
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
                ;


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), "!");
                    }
1400
                | arg
h2so5's avatar
h2so5 committed
1401 1402 1403 1404 1405
                ;

expr_value      : expr
                    {
                      if (!$1) $$ = new_nil(p);
1406 1407 1408 1409
                      else {
                        void_expr_error(p, $1);
                        $$ = $1;
                      }
h2so5's avatar
h2so5 committed
1410 1411 1412 1413 1414 1415 1416 1417
                    }
                ;

command_call    : command
                | block_command
                ;

block_command   : block_call
1418
                | block_call call_op2 operation2 command_args
h2so5's avatar
h2so5 committed
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
                ;

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);
                    }
1443
                | primary_value call_op operation2 command_args     %prec tLOWEST
h2so5's avatar
h2so5 committed
1444
                    {
1445
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
1446
                    }
1447
                | primary_value call_op operation2 command_args cmd_brace_block
h2so5's avatar
h2so5 committed
1448 1449
                    {
                      args_with_block(p, $4, $5);
1450
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
1451 1452 1453
                   }
                | primary_value tCOLON2 operation2 command_args %prec tLOWEST
                    {
1454
                      $$ = new_call(p, $1, $3, $4, tCOLON2);
h2so5's avatar
h2so5 committed
1455 1456 1457 1458
                    }
                | primary_value tCOLON2 operation2 command_args cmd_brace_block
                    {
                      args_with_block(p, $4, $5);
1459
                      $$ = new_call(p, $1, $3, $4, tCOLON2);
h2so5's avatar
h2so5 committed
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
                    }
                | 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
                    {
1496
                      $$ = $2;
h2so5's avatar
h2so5 committed
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
                    }
                ;

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
                    {
1545
                      $$ = new_masgn(p, $2, NULL);
h2so5's avatar
h2so5 committed
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
                    }
                ;

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
                    {
1575
                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
h2so5's avatar
h2so5 committed
1576
                    }
1577
                | primary_value call_op tIDENTIFIER
h2so5's avatar
h2so5 committed
1578
                    {
1579
                      $$ = new_call(p, $1, $3, 0, $2);
h2so5's avatar
h2so5 committed
1580 1581 1582
                    }
                | primary_value tCOLON2 tIDENTIFIER
                    {
1583
                      $$ = new_call(p, $1, $3, 0, tCOLON2);
h2so5's avatar
h2so5 committed
1584
                    }
1585
                | primary_value call_op tCONSTANT
h2so5's avatar
h2so5 committed
1586
                    {
1587
                      $$ = new_call(p, $1, $3, 0, $2);
h2so5's avatar
h2so5 committed
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
                    }
                | 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
                    {
1614
                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
h2so5's avatar
h2so5 committed
1615
                    }
1616
                | primary_value call_op tIDENTIFIER
h2so5's avatar
h2so5 committed
1617
                    {
1618
                      $$ = new_call(p, $1, $3, 0, $2);
h2so5's avatar
h2so5 committed
1619 1620 1621
                    }
                | primary_value tCOLON2 tIDENTIFIER
                    {
1622
                      $$ = new_call(p, $1, $3, 0, tCOLON2);
h2so5's avatar
h2so5 committed
1623
                    }
1624
                | primary_value call_op tCONSTANT
h2so5's avatar
h2so5 committed
1625
                    {
1626
                      $$ = new_call(p, $1, $3, 0, $2);
h2so5's avatar
h2so5 committed
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
                    }
                | 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
                ;

1742
arg             : lhs '=' arg_rhs
h2so5's avatar
h2so5 committed
1743 1744 1745
                    {
                      $$ = new_asgn(p, $1, $3);
                    }
1746
                | var_lhs tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1747 1748 1749
                    {
                      $$ = new_op_asgn(p, $1, $2, $3);
                    }
1750
                | primary_value '[' opt_call_args rbracket tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1751
                    {
1752
                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
h2so5's avatar
h2so5 committed
1753
                    }
1754
                | primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1755
                    {
1756
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5);
h2so5's avatar
h2so5 committed
1757
                    }
1758
                | primary_value call_op tCONSTANT tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1759
                    {
1760
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5);
h2so5's avatar
h2so5 committed
1761
                    }
1762
                | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1763
                    {
1764
                      $$ = new_op_asgn(p, new_call(p, $1, $3, 0, tCOLON2), $4, $5);
h2so5's avatar
h2so5 committed
1765
                    }
1766
                | primary_value tCOLON2 tCONSTANT tOP_ASGN arg_rhs
h2so5's avatar
h2so5 committed
1767 1768 1769 1770
                    {
                      yyerror(p, "constant re-assignment");
                      $$ = new_begin(p, 0);
                    }
1771
                | tCOLON3 tCONSTANT tOP_ASGN arg_rhs
1772 1773 1774 1775
                    {
                      yyerror(p, "constant re-assignment");
                      $$ = new_begin(p, 0);
                    }
1776
                | backref tOP_ASGN arg_rhs
1777 1778 1779 1780
                    {
                      backref_error(p, $1);
                      $$ = new_begin(p, 0);
                    }
h2so5's avatar
h2so5 committed
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
                | 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;
                    }
                ;

aref_args       : none
                | args trailer
                    {
                      $$ = $1;
1919
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1920
                    }
1921
                | args comma assocs trailer
h2so5's avatar
h2so5 committed
1922 1923 1924 1925 1926 1927
                    {
                      $$ = push($1, new_hash(p, $3));
                    }
                | assocs trailer
                    {
                      $$ = cons(new_hash(p, $1), 0);
1928
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1929 1930 1931
                    }
                ;

1932
arg_rhs         : arg %prec tOP_ASGN
1933 1934 1935 1936
                    {
                      void_expr_error(p, $1);
                      $$ = $1;
                    }
1937 1938
                | arg modifier_rescue arg
                    {
1939
                      void_expr_error(p, $1);
1940 1941 1942 1943
                      $$ = new_mod_rescue(p, $1, $3);
                    }
                ;

h2so5's avatar
h2so5 committed
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
paren_args      : '(' opt_call_args rparen
                    {
                      $$ = $2;
                    }
                ;

opt_paren_args  : none
                | paren_args
                ;

opt_call_args   : none
                | call_args
                | args ','
                    {
                      $$ = cons($1,0);
1959
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1960
                    }
1961
                | args comma assocs ','
h2so5's avatar
h2so5 committed
1962 1963
                    {
                      $$ = cons(push($1, new_hash(p, $3)), 0);
1964
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1965 1966 1967 1968
                    }
                | assocs ','
                    {
                      $$ = cons(list1(new_hash(p, $1)), 0);
1969
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1970 1971 1972 1973 1974 1975
                    }
                ;

call_args       : command
                    {
                      $$ = cons(list1($1), 0);
1976
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1977 1978 1979 1980
                    }
                | args opt_block_arg
                    {
                      $$ = cons($1, $2);
1981
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1982 1983 1984 1985
                    }
                | assocs opt_block_arg
                    {
                      $$ = cons(list1(new_hash(p, $1)), $2);
1986
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1987
                    }
1988
                | args comma assocs opt_block_arg
h2so5's avatar
h2so5 committed
1989 1990
                    {
                      $$ = cons(push($1, new_hash(p, $3)), $4);
1991
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1992 1993 1994 1995
                    }
                | block_arg
                    {
                      $$ = cons(0, $1);
1996
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
                    }
                ;

command_args    :  {
                      $<stack>$ = p->cmdarg_stack;
                      CMDARG_PUSH(1);
                    }
                  call_args
                    {
                      p->cmdarg_stack = $<stack>1;
                      $$ = $2;
                    }
                ;

2011
block_arg       : tAMPER arg
h2so5's avatar
h2so5 committed
2012 2013 2014 2015 2016
                    {
                      $$ = new_block_arg(p, $2);
                    }
                ;

2017
opt_block_arg   : comma block_arg
h2so5's avatar
h2so5 committed
2018 2019 2020 2021 2022 2023 2024 2025 2026
                    {
                      $$ = $2;
                    }
                | none
                    {
                      $$ = 0;
                    }
                ;

2027 2028 2029 2030
comma           : ','
                | ','  heredoc_bodies
                ;

2031
args            : arg
h2so5's avatar
h2so5 committed
2032
                    {
2033
                      void_expr_error(p, $1);
h2so5's avatar
h2so5 committed
2034
                      $$ = cons($1, 0);
2035
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2036
                    }
2037
                | tSTAR arg
h2so5's avatar
h2so5 committed
2038
                    {
2039
                      void_expr_error(p, $2);
h2so5's avatar
h2so5 committed
2040
                      $$ = cons(new_splat(p, $2), 0);
2041
                      NODE_LINENO($$, $2);
h2so5's avatar
h2so5 committed
2042
                    }
2043
                | args comma arg
h2so5's avatar
h2so5 committed
2044
                    {
2045
                      void_expr_error(p, $3);
h2so5's avatar
h2so5 committed
2046 2047
                      $$ = push($1, $3);
                    }
2048
                | args comma tSTAR arg
h2so5's avatar
h2so5 committed
2049
                    {
2050
                      void_expr_error(p, $4);
h2so5's avatar
h2so5 committed
2051 2052 2053 2054
                      $$ = push($1, new_splat(p, $4));
                    }
                ;

2055
mrhs            : args comma arg
h2so5's avatar
h2so5 committed
2056
                    {
2057
                      void_expr_error(p, $3);
h2so5's avatar
h2so5 committed
2058 2059
                      $$ = push($1, $3);
                    }
2060
                | args comma tSTAR arg
h2so5's avatar
h2so5 committed
2061
                    {
2062
                      void_expr_error(p, $4);
h2so5's avatar
h2so5 committed
2063 2064
                      $$ = push($1, new_splat(p, $4));
                    }
2065
                | tSTAR arg
h2so5's avatar
h2so5 committed
2066
                    {
2067
                      void_expr_error(p, $2);
h2so5's avatar
h2so5 committed
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
                      $$ = list1(new_splat(p, $2));
                    }
                ;

primary         : literal
                | string
                | xstring
                | regexp
                | heredoc
                | var_ref
                | backref
                | tFID
                    {
                      $$ = new_fcall(p, $1, 0);
                    }
                | keyword_begin
                    {
2085
                      $<stack>$ = p->cmdarg_stack;
h2so5's avatar
h2so5 committed
2086 2087 2088 2089 2090
                      p->cmdarg_stack = 0;
                    }
                  bodystmt
                  keyword_end
                    {
2091
                      p->cmdarg_stack = $<stack>2;
h2so5's avatar
h2so5 committed
2092 2093
                      $$ = $3;
                    }
2094
                | tLPAREN_ARG
h2so5's avatar
h2so5 committed
2095
                    {
2096
                      $<stack>$ = p->cmdarg_stack;
2097 2098
                      p->cmdarg_stack = 0;
                    }
2099
                  stmt {p->lstate = EXPR_ENDARG;} rparen
2100
                    {
2101
                      p->cmdarg_stack = $<stack>2;
2102
                      $$ = $3;
h2so5's avatar
h2so5 committed
2103 2104 2105
                    }
                | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen
                    {
2106
                      $$ = new_nil(p);
h2so5's avatar
h2so5 committed
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
                    }
                | 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);
2123
                      NODE_LINENO($$, $2);
h2so5's avatar
h2so5 committed
2124 2125 2126 2127
                    }
                | tLBRACE assoc_list '}'
                    {
                      $$ = new_hash(p, $2);
2128
                      NODE_LINENO($$, $2);
h2so5's avatar
h2so5 committed
2129 2130 2131 2132 2133
                    }
                | keyword_return
                    {
                      $$ = new_return(p, 0);
                    }
2134
                | keyword_yield opt_paren_args
h2so5's avatar
h2so5 committed
2135
                    {
2136
                      $$ = new_yield(p, $2);
h2so5's avatar
h2so5 committed
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
                    }
                | 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
2163 2164 2165 2166
                    {
                      $<stack>$ = p->cmdarg_stack;
                      p->cmdarg_stack = 0;
                    }
h2so5's avatar
h2so5 committed
2167 2168 2169
                  lambda_body
                    {
                      p->lpar_beg = $<num>2;
2170
                      $$ = new_lambda(p, $3, $5);
h2so5's avatar
h2so5 committed
2171
                      local_unnest(p);
2172
                      p->cmdarg_stack = $<stack>4;
2173
                      CMDARG_LEXPOP();
h2so5's avatar
h2so5 committed
2174 2175 2176 2177 2178 2179 2180
                    }
                | keyword_if expr_value then
                  compstmt
                  if_tail
                  keyword_end
                    {
                      $$ = new_if(p, cond($2), $4, $5);
2181
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2182 2183 2184 2185 2186 2187 2188
                    }
                | keyword_unless expr_value then
                  compstmt
                  opt_else
                  keyword_end
                    {
                      $$ = new_unless(p, cond($2), $4, $5);
2189
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2190 2191 2192 2193 2194 2195
                    }
                | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
                  compstmt
                  keyword_end
                    {
                      $$ = new_while(p, cond($3), $6);
2196
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2197 2198 2199 2200 2201 2202
                    }
                | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();}
                  compstmt
                  keyword_end
                    {
                      $$ = new_until(p, cond($3), $6);
2203
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222
                    }
                | 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);
2223
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
                    }
                | keyword_class
                  cpath superclass
                    {
                      if (p->in_def || p->in_single)
                        yyerror(p, "class definition in method body");
                      $<nd>$ = local_switch(p);
                    }
                  bodystmt
                  keyword_end
                    {
2235 2236 2237
                      $$ = new_class(p, $2, $3, $5);
                      SET_LINENO($$, $1);
                      local_resume(p, $<nd>4);
h2so5's avatar
h2so5 committed
2238 2239 2240 2241 2242 2243 2244 2245 2246
                    }
                | keyword_class
                  tLSHFT expr
                    {
                      $<num>$ = p->in_def;
                      p->in_def = 0;
                    }
                  term
                    {
2247
                      $<nd>$ = cons(local_switch(p), nint(p->in_single));
h2so5's avatar
h2so5 committed
2248 2249 2250 2251 2252
                      p->in_single = 0;
                    }
                  bodystmt
                  keyword_end
                    {
2253 2254 2255 2256
                      $$ = new_sclass(p, $3, $7);
                      SET_LINENO($$, $1);
                      local_resume(p, $<nd>6->car);
                      p->in_def = $<num>4;
2257
                      p->in_single = intn($<nd>6->cdr);
h2so5's avatar
h2so5 committed
2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268
                    }
                | keyword_module
                  cpath
                    {
                      if (p->in_def || p->in_single)
                        yyerror(p, "module definition in method body");
                      $<nd>$ = local_switch(p);
                    }
                  bodystmt
                  keyword_end
                    {
2269 2270 2271
                      $$ = new_module(p, $2, $4);
                      SET_LINENO($$, $1);
                      local_resume(p, $<nd>3);
h2so5's avatar
h2so5 committed
2272 2273
                    }
                | keyword_def fname
2274 2275 2276 2277
                    {
                      $<stack>$ = p->cmdarg_stack;
                      p->cmdarg_stack = 0;
                    }
h2so5's avatar
h2so5 committed
2278 2279 2280 2281 2282 2283 2284 2285
                    {
                      p->in_def++;
                      $<nd>$ = local_switch(p);
                    }
                  f_arglist
                  bodystmt
                  keyword_end
                    {
2286 2287 2288
                      $$ = new_def(p, $2, $5, $6);
                      SET_LINENO($$, $1);
                      local_resume(p, $<nd>4);
h2so5's avatar
h2so5 committed
2289
                      p->in_def--;
2290
                      p->cmdarg_stack = $<stack>3;
h2so5's avatar
h2so5 committed
2291
                    }
2292 2293 2294 2295 2296 2297 2298
                | keyword_def singleton dot_or_colon
                    {
                      p->lstate = EXPR_FNAME;
                      $<stack>$ = p->cmdarg_stack;
                      p->cmdarg_stack = 0;
                    }
                    fname
h2so5's avatar
h2so5 committed
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
                    {
                      p->in_single++;
                      p->lstate = EXPR_ENDFN; /* force for args */
                      $<nd>$ = local_switch(p);
                    }
                  f_arglist
                  bodystmt
                  keyword_end
                    {
                      $$ = new_sdef(p, $2, $5, $7, $8);
2309
                      SET_LINENO($$, $1);
h2so5's avatar
h2so5 committed
2310 2311
                      local_resume(p, $<nd>6);
                      p->in_single--;
2312
                      p->cmdarg_stack = $<stack>4;
h2so5's avatar
h2so5 committed
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450
                    }
                | 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 ','
                    {
2451
                      $$ = new_args(p, $1, 0, 0, 0, 0);
h2so5's avatar
h2so5 committed
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578
                    }
                | 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 '|'
                    {
                      $$ = 0;
                    }
                | tOROP
                    {
                      $$ = 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;
                    }
2579
                | block_call call_op2 operation2 opt_paren_args
h2so5's avatar
h2so5 committed
2580
                    {
2581
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
2582
                    }
2583
                | block_call call_op2 operation2 opt_paren_args brace_block
h2so5's avatar
h2so5 committed
2584
                    {
2585
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
2586 2587
                      call_with_block(p, $$, $5);
                    }
2588
                | block_call call_op2 operation2 command_args do_block
h2so5's avatar
h2so5 committed
2589
                    {
2590
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
2591 2592 2593 2594 2595 2596 2597 2598
                      call_with_block(p, $$, $5);
                    }
                ;

method_call     : operation paren_args
                    {
                      $$ = new_fcall(p, $1, $2);
                    }
2599
                | primary_value call_op operation2 opt_paren_args
h2so5's avatar
h2so5 committed
2600
                    {
2601
                      $$ = new_call(p, $1, $3, $4, $2);
h2so5's avatar
h2so5 committed
2602 2603 2604
                    }
                | primary_value tCOLON2 operation2 paren_args
                    {
2605
                      $$ = new_call(p, $1, $3, $4, tCOLON2);
h2so5's avatar
h2so5 committed
2606 2607 2608
                    }
                | primary_value tCOLON2 operation3
                    {
2609
                      $$ = new_call(p, $1, $3, 0, tCOLON2);
h2so5's avatar
h2so5 committed
2610
                    }
2611
                | primary_value call_op paren_args
h2so5's avatar
h2so5 committed
2612
                    {
2613
                      $$ = new_call(p, $1, intern("call",4), $3, $2);
h2so5's avatar
h2so5 committed
2614 2615 2616
                    }
                | primary_value tCOLON2 paren_args
                    {
2617
                      $$ = new_call(p, $1, intern("call",4), $3, tCOLON2);
h2so5's avatar
h2so5 committed
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
                    }
                | keyword_super paren_args
                    {
                      $$ = new_super(p, $2);
                    }
                | keyword_super
                    {
                      $$ = new_zsuper(p);
                    }
                | primary_value '[' opt_call_args rbracket
                    {
2629
                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
h2so5's avatar
h2so5 committed
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688
                    }
                ;

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
                ;

2689
exc_list        : arg
h2so5's avatar
h2so5 committed
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727
                    {
                        $$ = 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));
                    }
                ;
mimaki's avatar
mimaki committed
2728

2729
string_rep      : string_interp
h2so5's avatar
h2so5 committed
2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782
                | 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
                ;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
2783

h2so5's avatar
h2so5 committed
2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
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);
                    }
                ;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
2799

FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
2800
heredoc_string_rep : heredoc_string_interp
h2so5's avatar
h2so5 committed
2801 2802
                   | heredoc_string_rep heredoc_string_interp
                   ;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
2803 2804

heredoc_string_interp : tHD_STRING_MID
h2so5's avatar
h2so5 committed
2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838
                    {
                      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);
                    }
2839
                | tSYMBEG tSTRING_BEG string_rep tSTRING
h2so5's avatar
h2so5 committed
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
                    {
                      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);
yui-knk's avatar
yui-knk committed
2928
                    }
h2so5's avatar
h2so5 committed
2929 2930 2931
                | keyword_true
                    {
                      $$ = new_true(p);
yui-knk's avatar
yui-knk committed
2932
                    }
h2so5's avatar
h2so5 committed
2933 2934 2935
                | keyword_false
                    {
                      $$ = new_false(p);
yui-knk's avatar
yui-knk committed
2936
                    }
h2so5's avatar
h2so5 committed
2937 2938
                | keyword__FILE__
                    {
2939 2940 2941
                      const char *fn = p->filename;
                      if (!fn) {
                        fn = "(null)";
h2so5's avatar
h2so5 committed
2942
                      }
2943
                      $$ = new_str(p, fn, strlen(fn));
h2so5's avatar
h2so5 committed
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957
                    }
                | keyword__LINE__
                    {
                      char buf[16];

                      snprintf(buf, sizeof(buf), "%d", p->lineno);
                      $$ = new_int(p, buf, 10);
                    }
                ;

backref         : tNTH_REF
                | tBACK_REF
                ;

2958
superclass      : /* term */
h2so5's avatar
h2so5 committed
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969
                    {
                      $$ = 0;
                    }
                | '<'
                    {
                      p->lstate = EXPR_BEG;
                      p->cmd_start = TRUE;
                    }
                  expr_value term
                    {
                      $$ = $3;
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
2970
                    } /*
h2so5's avatar
h2so5 committed
2971 2972 2973 2974
                | error term
                    {
                      yyerrok;
                      $$ = 0;
2975
                    } */
h2so5's avatar
h2so5 committed
2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105
                ;

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

3106
f_opt_asgn      : tIDENTIFIER '='
h2so5's avatar
h2so5 committed
3107 3108
                    {
                      local_add_f(p, $1);
3109 3110 3111 3112
                      $$ = $1;
                    }
                ;

3113
f_opt           : f_opt_asgn arg
3114
                    {
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
3115
                      $$ = cons(nsym($1), $2);
h2so5's avatar
h2so5 committed
3116 3117 3118
                    }
                ;

3119
f_block_opt     : f_opt_asgn primary_value
h2so5's avatar
h2so5 committed
3120
                    {
3121
                      $$ = cons(nsym($1), $2);
h2so5's avatar
h2so5 committed
3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193
                    }
                ;

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 {
3194
                        switch ((enum node_type)intn($3->car)) {
h2so5's avatar
h2so5 committed
3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222
                        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);
3223
                      NODE_LINENO($$, $1);
h2so5's avatar
h2so5 committed
3224 3225 3226 3227 3228 3229 3230
                    }
                | assocs ',' assoc
                    {
                      $$ = push($1, $3);
                    }
                ;

3231
assoc           : arg tASSOC arg
h2so5's avatar
h2so5 committed
3232 3233 3234
                    {
                      $$ = cons($1, $3);
                    }
3235
                | tLABEL arg
h2so5's avatar
h2so5 committed
3236 3237 3238
                    {
                      $$ = cons(new_sym(p, $1), $2);
                    }
3239
                | tLABEL_END arg
3240 3241 3242
                    {
                      $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
                    }
3243
                | tSTRING_BEG tLABEL_END arg
3244 3245 3246
                    {
                      $$ = cons(new_sym(p, new_strsym(p, $2)), $3);
                    }
3247
                | tSTRING_BEG string_rep tLABEL_END arg
3248 3249 3250
                    {
                      $$ = cons(new_dsym(p, push($2, $3)), $4);
                    }
h2so5's avatar
h2so5 committed
3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272
                ;

operation       : tIDENTIFIER
                | tCONSTANT
                | tFID
                ;

operation2      : tIDENTIFIER
                | tCONSTANT
                | tFID
                | op
                ;

operation3      : tIDENTIFIER
                | tFID
                | op
                ;

dot_or_colon    : '.'
                | tCOLON2
                ;

3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289
call_op         : '.'
                    {
                      $$ = '.';
                    }
                | tANDDOT
                    {
                      $$ = 0;
                    }
                ;

call_op2        : call_op
                | tCOLON2
                    {
                      $$ = tCOLON2;
                    }
                ;

h2so5's avatar
h2so5 committed
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305
opt_terms       : /* none */
                | terms
                ;

opt_nl          : /* none */
                | nl
                ;

rparen          : opt_nl ')'
                ;

rbracket        : opt_nl ']'
                ;

trailer         : /* none */
                | nl
3306
                | comma
h2so5's avatar
h2so5 committed
3307 3308 3309 3310
                ;

term            : ';' {yyerrok;}
                | nl
3311
                | heredoc_body
h2so5's avatar
h2so5 committed
3312 3313 3314 3315 3316 3317 3318
                ;

nl              : '\n'
                    {
                      p->lineno++;
                      p->column = 0;
                    }
3319
                ;
h2so5's avatar
h2so5 committed
3320 3321

terms           : term
3322
                | terms term
h2so5's avatar
h2so5 committed
3323 3324 3325 3326 3327 3328 3329
                ;

none            : /* none */
                    {
                      $$ = 0;
                    }
                ;
mimaki's avatar
mimaki committed
3330
%%
3331
#define pylval  (*((YYSTYPE*)(p->ylval)))
mimaki's avatar
mimaki committed
3332 3333 3334 3335

static void
yyerror(parser_state *p, const char *s)
{
3336
  char* c;
3337
  int n;
3338 3339

  if (! p->capture_errors) {
3340
#ifndef MRB_DISABLE_STDIO
3341
    if (p->filename) {
3342
      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
3343 3344
    }
    else {
3345
      fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
3346
    }
3347
#endif
3348 3349 3350
  }
  else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) {
    n = strlen(s);
Max Anselm's avatar
Max Anselm committed
3351
    c = (char *)parser_palloc(p, n + 1);
3352 3353 3354
    memcpy(c, s, n + 1);
    p->error_buffer[p->nerr].message = c;
    p->error_buffer[p->nerr].lineno = p->lineno;
3355
    p->error_buffer[p->nerr].column = p->column;
3356
  }
mimaki's avatar
mimaki committed
3357 3358 3359 3360 3361 3362 3363 3364
  p->nerr++;
}

static void
yyerror_i(parser_state *p, const char *fmt, int i)
{
  char buf[256];

3365
  snprintf(buf, sizeof(buf), fmt, i);
mimaki's avatar
mimaki committed
3366 3367 3368 3369 3370 3371
  yyerror(p, buf);
}

static void
yywarn(parser_state *p, const char *s)
{
3372
  char* c;
3373
  int n;
3374 3375

  if (! p->capture_errors) {
3376
#ifndef MRB_DISABLE_STDIO
3377
    if (p->filename) {
3378
      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
3379 3380
    }
    else {
3381
      fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
3382
    }
3383
#endif
3384
  }
3385
  else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) {
3386
    n = strlen(s);
Max Anselm's avatar
Max Anselm committed
3387
    c = (char *)parser_palloc(p, n + 1);
3388
    memcpy(c, s, n + 1);
3389 3390 3391
    p->warn_buffer[p->nwarn].message = c;
    p->warn_buffer[p->nwarn].lineno = p->lineno;
    p->warn_buffer[p->nwarn].column = p->column;
3392 3393
  }
  p->nwarn++;
mimaki's avatar
mimaki committed
3394 3395 3396 3397 3398
}

static void
yywarning(parser_state *p, const char *s)
{
3399
  yywarn(p, s);
mimaki's avatar
mimaki committed
3400 3401 3402 3403 3404 3405 3406
}

static void
yywarning_s(parser_state *p, const char *fmt, const char *s)
{
  char buf[256];

3407
  snprintf(buf, sizeof(buf), fmt, s);
mimaki's avatar
mimaki committed
3408 3409 3410 3411 3412 3413
  yywarning(p, buf);
}

static void
backref_error(parser_state *p, node *n)
{
3414 3415 3416 3417 3418
  int c;

  c = (int)(intptr_t)n->car;

  if (c == NODE_NTH_REF) {
3419
    yyerror_i(p, "can't set variable $%" MRB_PRId, (mrb_int)(intptr_t)n->cdr);
3420 3421
  }
  else if (c == NODE_BACK_REF) {
3422
    yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
3423 3424
  }
  else {
3425
    mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
mimaki's avatar
mimaki committed
3426 3427 3428
  }
}

3429 3430 3431 3432 3433
static void
void_expr_error(parser_state *p, node *n)
{
  int c;

3434
  if (n == NULL) return;
3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
  c = (int)(intptr_t)n->car;
  switch (c) {
  case NODE_BREAK:
  case NODE_RETURN:
  case NODE_NEXT:
  case NODE_REDO:
  case NODE_RETRY:
    yyerror(p, "void value expression");
    break;
  default:
    break;
  }
}

3449
static void pushback(parser_state *p, int c);
cremno's avatar
cremno committed
3450 3451
static mrb_bool peeks(parser_state *p, const char *s);
static mrb_bool skips(parser_state *p, const char *s);
mimaki's avatar
mimaki committed
3452 3453 3454 3455 3456 3457 3458 3459 3460

static inline int
nextc(parser_state *p)
{
  int c;

  if (p->pb) {
    node *tmp;

3461
    c = (int)(intptr_t)p->pb->car;
mimaki's avatar
mimaki committed
3462 3463 3464 3465 3466
    tmp = p->pb;
    p->pb = p->pb->cdr;
    cons_free(tmp);
  }
  else {
3467
#ifndef MRB_DISABLE_STDIO
3468
    if (p->f) {
3469
      if (feof(p->f)) goto eof;
3470
      c = fgetc(p->f);
3471
      if (c == EOF) goto eof;
3472
    }
3473 3474
    else
#endif
h2so5's avatar
h2so5 committed
3475 3476 3477 3478 3479 3480
      if (!p->s || p->s >= p->send) {
        goto eof;
      }
      else {
        c = (unsigned char)*p->s++;
      }
mimaki's avatar
mimaki committed
3481
  }
3482 3483 3484
  if (c >= 0) {
    p->column++;
  }
3485 3486 3487 3488 3489 3490 3491 3492
  if (c == '\r') {
    c = nextc(p);
    if (c != '\n') {
      pushback(p, c);
      return '\r';
    }
    return c;
  }
mimaki's avatar
mimaki committed
3493
  return c;
3494

h2so5's avatar
h2so5 committed
3495
  eof:
3496 3497
  if (!p->cxt) return -1;
  else {
3498
    if (p->cxt->partial_hook(p) < 0)
3499 3500
      return -1;                /* end of program(s) */
    return -2;                  /* end of a file in the program files */
3501
  }
mimaki's avatar
mimaki committed
3502 3503 3504 3505 3506
}

static void
pushback(parser_state *p, int c)
{
3507 3508 3509
  if (c >= 0) {
    p->column--;
  }
3510
  p->pb = cons((node*)(intptr_t)c, p->pb);
mimaki's avatar
mimaki committed
3511 3512 3513 3514 3515 3516 3517
}

static void
skip(parser_state *p, char term)
{
  int c;

3518 3519 3520 3521 3522
  for (;;) {
    c = nextc(p);
    if (c < 0) break;
    if (c == term) break;
  }
mimaki's avatar
mimaki committed
3523 3524
}

Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
3525 3526
static int
peekc_n(parser_state *p, int n)
mimaki's avatar
mimaki committed
3527 3528 3529 3530
{
  node *list = 0;
  int c0;

3531
  do {
mimaki's avatar
mimaki committed
3532
    c0 = nextc(p);
3533
    if (c0 == -1) return c0;    /* do not skip partial EOF */
3534
    if (c0 >= 0) --p->column;
3535
    list = push(list, (node*)(intptr_t)c0);
3536
  } while(n--);
mimaki's avatar
mimaki committed
3537
  if (p->pb) {
3538
    p->pb = append((node*)list, p->pb);
mimaki's avatar
mimaki committed
3539 3540 3541 3542
  }
  else {
    p->pb = list;
  }
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
3543 3544 3545 3546 3547 3548 3549
  return c0;
}

static mrb_bool
peek_n(parser_state *p, int c, int n)
{
  return peekc_n(p, n) == c && c >= 0;
mimaki's avatar
mimaki committed
3550 3551 3552
}
#define peek(p,c) peek_n((p), (c), 0)

cremno's avatar
cremno committed
3553
static mrb_bool
mimaki's avatar
mimaki committed
3554 3555 3556 3557
peeks(parser_state *p, const char *s)
{
  int len = strlen(s);

3558
#ifndef MRB_DISABLE_STDIO
mimaki's avatar
mimaki committed
3559 3560 3561 3562 3563 3564 3565
  if (p->f) {
    int n = 0;
    while (*s) {
      if (!peek_n(p, *s++, n++)) return FALSE;
    }
    return TRUE;
  }
3566 3567
  else
#endif
3568
    if (p->s && p->s + len <= p->send) {
h2so5's avatar
h2so5 committed
3569 3570
      if (memcmp(p->s, s, len) == 0) return TRUE;
    }
mimaki's avatar
mimaki committed
3571 3572 3573
  return FALSE;
}

cremno's avatar
cremno committed
3574
static mrb_bool
mimaki's avatar
mimaki committed
3575 3576 3577 3578 3579
skips(parser_state *p, const char *s)
{
  int c;

  for (;;) {
3580
    /* skip until first char */
mimaki's avatar
mimaki committed
3581 3582 3583
    for (;;) {
      c = nextc(p);
      if (c < 0) return c;
3584 3585 3586 3587
      if (c == '\n') {
        p->lineno++;
        p->column = 0;
      }
mimaki's avatar
mimaki committed
3588 3589 3590 3591 3592 3593 3594
      if (c == *s) break;
    }
    s++;
    if (peeks(p, s)) {
      int len = strlen(s);

      while (len--) {
3595 3596 3597 3598
        if (nextc(p) == '\n') {
          p->lineno++;
          p->column = 0;
        }
mimaki's avatar
mimaki committed
3599 3600
      }
      return TRUE;
3601
    }
h2so5's avatar
h2so5 committed
3602
    else{
3603
      s--;
mimaki's avatar
mimaki committed
3604 3605 3606 3607 3608 3609
    }
  }
  return FALSE;
}


3610
static int
mimaki's avatar
mimaki committed
3611 3612
newtok(parser_state *p)
{
3613 3614 3615 3616 3617 3618
  if (p->tokbuf != p->buf) {
    mrb_free(p->mrb, p->tokbuf);
    p->tokbuf = p->buf;
    p->tsiz = MRB_PARSER_TOKBUF_SIZE;
  }
  p->tidx = 0;
3619
  return p->column - 1;
mimaki's avatar
mimaki committed
3620 3621 3622
}

static void
3623
tokadd(parser_state *p, int32_t c)
mimaki's avatar
mimaki committed
3624
{
3625
  char utf8[4];
3626
  int i, len;
3627 3628 3629 3630 3631 3632

  /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */
  if (c >= 0) {
    /* Single byte from source or non-Unicode escape */
    utf8[0] = (char)c;
    len = 1;
3633 3634
  }
  else {
3635 3636 3637 3638 3639
    /* Unicode character */
    c = -c;
    if (c < 0x80) {
      utf8[0] = (char)c;
      len = 1;
3640 3641
    }
    else if (c < 0x800) {
3642 3643 3644
      utf8[0] = (char)(0xC0 | (c >> 6));
      utf8[1] = (char)(0x80 | (c & 0x3F));
      len = 2;
3645 3646
    }
    else if (c < 0x10000) {
3647 3648 3649 3650
      utf8[0] = (char)(0xE0 |  (c >> 12)        );
      utf8[1] = (char)(0x80 | ((c >>  6) & 0x3F));
      utf8[2] = (char)(0x80 | ( c        & 0x3F));
      len = 3;
3651 3652
    }
    else {
3653 3654 3655 3656 3657 3658 3659
      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;
    }
  }
3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671
  if (p->tidx+len >= p->tsiz) {
    if (p->tsiz >= MRB_PARSER_TOKBUF_MAX) {
      p->tidx += len;
      return;
    }
    p->tsiz *= 2;
    if (p->tokbuf == p->buf) {
      p->tokbuf = (char*)mrb_malloc(p->mrb, p->tsiz);
      memcpy(p->tokbuf, p->buf, MRB_PARSER_TOKBUF_SIZE);
    }
    else {
      p->tokbuf = (char*)mrb_realloc(p->mrb, p->tokbuf, p->tsiz);
3672
    }
mimaki's avatar
mimaki committed
3673
  }
3674 3675 3676
  for (i = 0; i < len; i++) {
    p->tokbuf[p->tidx++] = utf8[i];
  }
mimaki's avatar
mimaki committed
3677 3678 3679 3680 3681
}

static int
toklast(parser_state *p)
{
3682
  return p->tokbuf[p->tidx-1];
mimaki's avatar
mimaki committed
3683 3684 3685 3686 3687
}

static void
tokfix(parser_state *p)
{
3688 3689
  if (p->tidx >= MRB_PARSER_TOKBUF_MAX) {
    p->tidx = MRB_PARSER_TOKBUF_MAX-1;
mimaki's avatar
mimaki committed
3690 3691
    yyerror(p, "string too long (truncated)");
  }
3692
  p->tokbuf[p->tidx] = '\0';
mimaki's avatar
mimaki committed
3693 3694 3695 3696 3697
}

static const char*
tok(parser_state *p)
{
3698
  return p->tokbuf;
mimaki's avatar
mimaki committed
3699 3700 3701 3702 3703
}

static int
toklen(parser_state *p)
{
3704
  return p->tidx;
mimaki's avatar
mimaki committed
3705 3706 3707 3708 3709 3710 3711 3712 3713
}

#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))

3714
static int
3715
scan_oct(const int *start, int len, int *retlen)
mimaki's avatar
mimaki committed
3716
{
3717
  const int *s = start;
3718
  int retval = 0;
mimaki's avatar
mimaki committed
3719

fleuria's avatar
fleuria committed
3720
  /* mrb_assert(len <= 3) */
mimaki's avatar
mimaki committed
3721 3722 3723 3724 3725
  while (len-- && *s >= '0' && *s <= '7') {
    retval <<= 3;
    retval |= *s++ - '0';
  }
  *retlen = s - start;
3726

mimaki's avatar
mimaki committed
3727 3728 3729
  return retval;
}

3730
static int32_t
3731
scan_hex(const int *start, int len, int *retlen)
mimaki's avatar
mimaki committed
3732 3733
{
  static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
3734
  const int *s = start;
3735
  int32_t retval = 0;
mimaki's avatar
mimaki committed
3736 3737
  char *tmp;

3738
  /* mrb_assert(len <= 8) */
3739
  while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) {
mimaki's avatar
mimaki committed
3740 3741 3742 3743 3744
    retval <<= 4;
    retval |= (tmp - hexdigit) & 15;
    s++;
  }
  *retlen = s - start;
3745

mimaki's avatar
mimaki committed
3746 3747 3748
  return retval;
}

3749
static int32_t
3750
read_escape_unicode(parser_state *p, int limit)
3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786
{
  int32_t c;
  int buf[9];
  int i;

  /* Look for opening brace */
  i = 0;
  buf[0] = nextc(p);
  if (buf[0] < 0) goto eof;
  if (ISXDIGIT(buf[0])) {
    /* \uxxxx form */
    for (i=1; i<limit; i++) {
      buf[i] = nextc(p);
      if (buf[i] < 0) goto eof;
      if (!ISXDIGIT(buf[i])) {
        pushback(p, buf[i]);
        break;
      }
    }
  }
  else {
    pushback(p, buf[0]);
  }
  c = scan_hex(buf, i, &i);
  if (i == 0) {
  eof:
    yyerror(p, "Invalid escape character syntax");
    return -1;
  }
  if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
    yyerror(p, "Invalid Unicode code point");
    return -1;
  }
  return c;
}

3787 3788
/* Return negative to indicate Unicode code point */
static int32_t
mimaki's avatar
mimaki committed
3789 3790
read_escape(parser_state *p)
{
3791
  int32_t c;
mimaki's avatar
mimaki committed
3792 3793

  switch (c = nextc(p)) {
h2so5's avatar
h2so5 committed
3794
  case '\\':/* Backslash */
mimaki's avatar
mimaki committed
3795 3796
    return c;

h2so5's avatar
h2so5 committed
3797
  case 'n':/* newline */
mimaki's avatar
mimaki committed
3798 3799
    return '\n';

h2so5's avatar
h2so5 committed
3800
  case 't':/* horizontal tab */
mimaki's avatar
mimaki committed
3801 3802
    return '\t';

h2so5's avatar
h2so5 committed
3803
  case 'r':/* carriage-return */
mimaki's avatar
mimaki committed
3804 3805
    return '\r';

h2so5's avatar
h2so5 committed
3806
  case 'f':/* form-feed */
mimaki's avatar
mimaki committed
3807 3808
    return '\f';

h2so5's avatar
h2so5 committed
3809
  case 'v':/* vertical tab */
mimaki's avatar
mimaki committed
3810 3811
    return '\13';

h2so5's avatar
h2so5 committed
3812
  case 'a':/* alarm(bell) */
mimaki's avatar
mimaki committed
3813 3814
    return '\007';

h2so5's avatar
h2so5 committed
3815
  case 'e':/* escape */
mimaki's avatar
mimaki committed
3816 3817 3818 3819
    return 033;

  case '0': case '1': case '2': case '3': /* octal constant */
  case '4': case '5': case '6': case '7':
h2so5's avatar
h2so5 committed
3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830
  {
    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;
Masaki Muranaka's avatar
Masaki Muranaka committed
3831
      }
mimaki's avatar
mimaki committed
3832
    }
h2so5's avatar
h2so5 committed
3833 3834 3835
    c = scan_oct(buf, i, &i);
  }
  return c;
mimaki's avatar
mimaki committed
3836

h2so5's avatar
h2so5 committed
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847
  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;
mimaki's avatar
mimaki committed
3848 3849
      }
    }
h2so5's avatar
h2so5 committed
3850 3851 3852 3853 3854 3855 3856
    c = scan_hex(buf, i, &i);
    if (i == 0) {
      yyerror(p, "Invalid escape character syntax");
      return 0;
    }
  }
  return c;
mimaki's avatar
mimaki committed
3857

3858
  case 'u':     /* Unicode */
3859
    if (peek(p, '{')) {
3860
      /* \u{xxxxxxxx} form */
3861 3862 3863 3864
      nextc(p);
      c = read_escape_unicode(p, 8);
      if (c < 0) return 0;
      if (nextc(p) != '}') goto eof;
3865 3866
    }
    else {
3867 3868
      c = read_escape_unicode(p, 4);
      if (c < 0) return 0;
3869 3870 3871
    }
  return -c;

h2so5's avatar
h2so5 committed
3872
  case 'b':/* backspace */
mimaki's avatar
mimaki committed
3873 3874
    return '\010';

h2so5's avatar
h2so5 committed
3875
  case 's':/* space */
mimaki's avatar
mimaki committed
3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886
    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;
    }
3887
    else if (c < 0) goto eof;
mimaki's avatar
mimaki committed
3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903
    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;
3904
    else if (c < 0) goto eof;
mimaki's avatar
mimaki committed
3905 3906
    return c & 0x9f;

h2so5's avatar
h2so5 committed
3907
    eof:
mimaki's avatar
mimaki committed
3908
  case -1:
3909
  case -2:                      /* end of a file */
mimaki's avatar
mimaki committed
3910 3911 3912 3913 3914 3915 3916 3917 3918
    yyerror(p, "Invalid escape character syntax");
    return '\0';

  default:
    return c;
  }
}

static int
3919
parse_string(parser_state *p)
mimaki's avatar
mimaki committed
3920 3921
{
  int c;
3922 3923 3924 3925 3926
  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;
3927
  int cmd_state = p->cmd_start;
mimaki's avatar
mimaki committed
3928

3929 3930
  if (beg == 0) beg = -3;       /* should never happen */
  if (end == 0) end = -3;
mimaki's avatar
mimaki committed
3931
  newtok(p);
3932
  while ((c = nextc(p)) != end || nest_level != 0) {
3933
    if (hinf && (c == '\n' || c < 0)) {
3934
      mrb_bool line_head;
3935 3936 3937 3938 3939 3940 3941
      tokadd(p, '\n');
      tokfix(p);
      p->lineno++;
      p->column = 0;
      line_head = hinf->line_head;
      hinf->line_head = TRUE;
      if (line_head) {
h2so5's avatar
h2so5 committed
3942 3943 3944 3945 3946 3947 3948 3949 3950 3951
        /* 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)) {
3952 3953 3954 3955 3956 3957
          if (c < 0) {
            p->parsing_heredoc = NULL;
          }
          else {
            return tHEREDOC_END;
          }
h2so5's avatar
h2so5 committed
3958
        }
3959
      }
3960
      if (c < 0) {
h2so5's avatar
h2so5 committed
3961 3962 3963 3964
        char buf[256];
        snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
        yyerror(p, buf);
        return 0;
3965
      }
3966
      pylval.nd = new_str(p, tok(p), toklen(p));
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
3967
      return tHD_STRING_MID;
3968
    }
3969
    if (c < 0) {
mimaki's avatar
mimaki committed
3970 3971 3972
      yyerror(p, "unterminated string meets end of file");
      return 0;
    }
3973 3974 3975 3976 3977 3978 3979 3980
    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;
    }
mimaki's avatar
mimaki committed
3981 3982
    else if (c == '\\') {
      c = nextc(p);
3983
      if (type & STR_FUNC_EXPAND) {
h2so5's avatar
h2so5 committed
3984 3985 3986
        if (c == end || c == beg) {
          tokadd(p, c);
        }
3987
        else if (c == '\n') {
h2so5's avatar
h2so5 committed
3988 3989
          p->lineno++;
          p->column = 0;
3990 3991 3992
          if (type & STR_FUNC_ARRAY) {
            tokadd(p, '\n');
          }
h2so5's avatar
h2so5 committed
3993
        }
3994 3995 3996 3997
        else if (type & STR_FUNC_REGEXP) {
          tokadd(p, '\\');
          tokadd(p, c);
        }
3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011
        else if (c == 'u' && peek(p, '{')) {
          /* \u{xxxx xxxx xxxx} form */
          nextc(p);
          while (1) {
            do c = nextc(p); while (ISSPACE(c));
            if (c == '}') break;
            pushback(p, c);
            c = read_escape_unicode(p, 8);
            if (c < 0) break;
            tokadd(p, -c);
          }
          if (hinf)
            hinf->line_head = FALSE;
        }
h2so5's avatar
h2so5 committed
4012
        else {
4013 4014
          pushback(p, c);
          tokadd(p, read_escape(p));
h2so5's avatar
h2so5 committed
4015 4016 4017
          if (hinf)
            hinf->line_head = FALSE;
        }
4018 4019
      }
      else {
h2so5's avatar
h2so5 committed
4020
        if (c != beg && c != end) {
4021
          if (c == '\n') {
h2so5's avatar
h2so5 committed
4022 4023
            p->lineno++;
            p->column = 0;
4024 4025 4026
          }
          if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) {
            tokadd(p, '\\');
h2so5's avatar
h2so5 committed
4027 4028 4029
          }
        }
        tokadd(p, c);
mimaki's avatar
mimaki committed
4030 4031 4032
      }
      continue;
    }
4033
    else if ((c == '#') && (type & STR_FUNC_EXPAND)) {
mimaki's avatar
mimaki committed
4034 4035
      c = nextc(p);
      if (c == '{') {
h2so5's avatar
h2so5 committed
4036 4037 4038
        tokfix(p);
        p->lstate = EXPR_BEG;
        p->cmd_start = TRUE;
4039
        pylval.nd = new_str(p, tok(p), toklen(p));
h2so5's avatar
h2so5 committed
4040 4041 4042 4043 4044
        if (hinf) {
          hinf->line_head = FALSE;
          return tHD_STRING_PART;
        }
        return tSTRING_PART;
mimaki's avatar
mimaki committed
4045 4046 4047 4048 4049
      }
      tokadd(p, '#');
      pushback(p, c);
      continue;
    }
4050 4051
    if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) {
      if (toklen(p) == 0) {
h2so5's avatar
h2so5 committed
4052 4053 4054 4055 4056 4057 4058 4059 4060
        do {
          if (c == '\n') {
            p->lineno++;
            p->column = 0;
            heredoc_treat_nextline(p);
            if (p->parsing_heredoc != NULL) {
              return tHD_LITERAL_DELIM;
            }
          }
4061 4062
          c = nextc(p);
        } while (ISSPACE(c));
h2so5's avatar
h2so5 committed
4063 4064
        pushback(p, c);
        return tLITERAL_DELIM;
4065 4066
      }
      else {
h2so5's avatar
h2so5 committed
4067 4068
        pushback(p, c);
        tokfix(p);
4069
        pylval.nd = new_str(p, tok(p), toklen(p));
h2so5's avatar
h2so5 committed
4070
        return tSTRING_MID;
4071 4072
      }
    }
4073 4074 4075 4076
    if (c == '\n') {
      p->lineno++;
      p->column = 0;
    }
mimaki's avatar
mimaki committed
4077
    tokadd(p, c);
fleuria's avatar
fleuria committed
4078
  }
mimaki's avatar
mimaki committed
4079 4080 4081

  tokfix(p);
  p->lstate = EXPR_END;
4082
  end_strterm(p);
mattn's avatar
mattn committed
4083

mattn's avatar
mattn committed
4084
  if (type & STR_FUNC_XQUOTE) {
4085
    pylval.nd = new_xstr(p, tok(p), toklen(p));
mattn's avatar
mattn committed
4086 4087 4088
    return tXSTRING;
  }

4089
  if (type & STR_FUNC_REGEXP) {
4090
    int f = 0;
cremno's avatar
cremno committed
4091
    int re_opt;
4092
    char *s = strndup(tok(p), toklen(p));
Cremno's avatar
Cremno committed
4093 4094
    char flags[3];
    char *flag = flags;
4095 4096
    char enc = '\0';
    char *encp;
Cremno's avatar
Cremno committed
4097
    char *dup;
4098

4099
    newtok(p);
cremno's avatar
cremno committed
4100 4101
    while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) {
      switch (re_opt) {
4102 4103 4104
      case 'i': f |= 1; break;
      case 'x': f |= 2; break;
      case 'm': f |= 4; break;
4105 4106
      case 'u': f |= 16; break;
      case 'n': f |= 32; break;
cremno's avatar
cremno committed
4107
      default: tokadd(p, re_opt); break;
4108 4109
      }
    }
cremno's avatar
cremno committed
4110
    pushback(p, re_opt);
4111 4112 4113
    if (toklen(p)) {
      char msg[128];
      tokfix(p);
4114
      snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
h2so5's avatar
h2so5 committed
4115
          toklen(p) > 1 ? "s" : "", tok(p));
4116 4117
      yyerror(p, msg);
    }
Cremno's avatar
Cremno committed
4118 4119 4120 4121
    if (f != 0) {
      if (f & 1) *flag++ = 'i';
      if (f & 2) *flag++ = 'x';
      if (f & 4) *flag++ = 'm';
4122 4123
      if (f & 16) enc = 'u';
      if (f & 32) enc = 'n';
Cremno's avatar
Cremno committed
4124
    }
4125 4126
    if (flag > flags) {
      dup = strndup(flags, (size_t)(flag - flags));
4127 4128
    }
    else {
Cremno's avatar
Cremno committed
4129 4130
      dup = NULL;
    }
4131 4132
    if (enc) {
      encp = strndup(&enc, 1);
4133 4134
    }
    else {
4135 4136
      encp = NULL;
    }
4137
    pylval.nd = new_regx(p, s, dup, encp);
mattn's avatar
mattn committed
4138 4139 4140

    return tREGEXP;
  }
4141
  pylval.nd = new_str(p, tok(p), toklen(p));
4142 4143 4144 4145 4146 4147
  if (IS_LABEL_POSSIBLE()) {
    if (IS_LABEL_SUFFIX(0)) {
      p->lstate = EXPR_BEG;
      nextc(p);
      return tLABEL_END;
    }
4148 4149
  }

mimaki's avatar
mimaki committed
4150 4151
  return tSTRING;
}
fleuria's avatar
fleuria committed
4152

4153 4154 4155 4156 4157 4158

static int
heredoc_identifier(parser_state *p)
{
  int c;
  int type = str_heredoc;
cremno's avatar
cremno committed
4159 4160
  mrb_bool indent = FALSE;
  mrb_bool quote = FALSE;
4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177
  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);
4178
    while ((c = nextc(p)) >= 0 && c != term) {
4179
      if (c == '\n') {
h2so5's avatar
h2so5 committed
4180 4181
        c = -1;
        break;
4182
      }
4183 4184
      tokadd(p, c);
    }
4185
    if (c < 0) {
4186 4187 4188
      yyerror(p, "unterminated here document identifier");
      return 0;
    }
4189 4190
  }
  else {
4191
    if (c < 0) {
4192 4193
      return 0;                 /* missing here document identifier */
    }
4194 4195 4196 4197 4198 4199 4200 4201
    if (! identchar(c)) {
      pushback(p, c);
      if (indent) pushback(p, '-');
      return 0;
    }
    newtok(p);
    do {
      tokadd(p, c);
4202
    } while ((c = nextc(p)) >= 0 && identchar(c));
4203 4204 4205 4206 4207 4208 4209 4210 4211
    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;
4212
  info->type = (string_type)type;
4213 4214 4215
  info->allow_indent = indent;
  info->line_head = TRUE;
  info->doc = NULL;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4216
  p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
4217 4218
  p->lstate = EXPR_END;

4219
  pylval.nd = newnode;
4220 4221
  return tHEREDOC_BEG;
}
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4222

mimaki's avatar
mimaki committed
4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234
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)
{
4235
  int32_t c;
mimaki's avatar
mimaki committed
4236 4237 4238
  int space_seen = 0;
  int cmd_state;
  enum mrb_lex_state_enum last_state;
4239
  int token_column;
mimaki's avatar
mimaki committed
4240

4241 4242
  if (p->lex_strterm) {
    if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4243
      if (p->parsing_heredoc != NULL)
h2so5's avatar
h2so5 committed
4244
        return parse_string(p);
4245 4246 4247
    }
    else
      return parse_string(p);
mimaki's avatar
mimaki committed
4248 4249 4250
  }
  cmd_state = p->cmd_start;
  p->cmd_start = FALSE;
h2so5's avatar
h2so5 committed
4251
  retry:
mimaki's avatar
mimaki committed
4252 4253
  last_state = p->lstate;
  switch (c = nextc(p)) {
kano4's avatar
kano4 committed
4254 4255
  case '\004':  /* ^D */
  case '\032':  /* ^Z */
4256
  case '\0':    /* NUL */
kano4's avatar
kano4 committed
4257
  case -1:      /* end of script. */
4258 4259
    if (p->heredocs_from_nextline)
      goto maybe_heredoc;
mimaki's avatar
mimaki committed
4260 4261
    return 0;

kano4's avatar
kano4 committed
4262
  /* white spaces */
mimaki's avatar
mimaki committed
4263
  case ' ': case '\t': case '\f': case '\r':
kano4's avatar
kano4 committed
4264
  case '\13':   /* '\v' */
mimaki's avatar
mimaki committed
4265 4266 4267
    space_seen = 1;
    goto retry;

kano4's avatar
kano4 committed
4268
  case '#':     /* it's a comment */
mimaki's avatar
mimaki committed
4269
    skip(p, '\n');
h2so5's avatar
h2so5 committed
4270
    /* fall through */
4271
  case -2:      /* end of a file */
mimaki's avatar
mimaki committed
4272
  case '\n':
h2so5's avatar
h2so5 committed
4273
    maybe_heredoc:
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4274
    heredoc_treat_nextline(p);
h2so5's avatar
h2so5 committed
4275 4276 4277 4278 4279 4280 4281 4282
  switch (p->lstate) {
  case EXPR_BEG:
  case EXPR_FNAME:
  case EXPR_DOT:
  case EXPR_CLASS:
  case EXPR_VALUE:
    p->lineno++;
    p->column = 0;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4283
    if (p->parsing_heredoc != NULL) {
4284 4285 4286
      if (p->lex_strterm) {
        return parse_string(p);
      }
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
4287
    }
h2so5's avatar
h2so5 committed
4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305
    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;
mimaki's avatar
mimaki committed
4306
      }
h2so5's avatar
h2so5 committed
4307
    case -1:                  /* EOF */
4308
    case -2:                  /* end of a file */
h2so5's avatar
h2so5 committed
4309 4310 4311 4312
      goto normal_newline;
    default:
      pushback(p, c);
      goto normal_newline;
mimaki's avatar
mimaki committed
4313
    }
h2so5's avatar
h2so5 committed
4314
  }
mimaki's avatar
mimaki committed
4315
  normal_newline:
h2so5's avatar
h2so5 committed
4316 4317 4318
  p->cmd_start = TRUE;
  p->lstate = EXPR_BEG;
  return '\n';
mimaki's avatar
mimaki committed
4319 4320 4321 4322

  case '*':
    if ((c = nextc(p)) == '*') {
      if ((c = nextc(p)) == '=') {
4323
        pylval.id = intern("**",2);
h2so5's avatar
h2so5 committed
4324 4325
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4326 4327 4328 4329 4330 4331
      }
      pushback(p, c);
      c = tPOW;
    }
    else {
      if (c == '=') {
4332
        pylval.id = intern_c('*');
h2so5's avatar
h2so5 committed
4333 4334
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4335 4336 4337
      }
      pushback(p, c);
      if (IS_SPCARG(c)) {
4338
        yywarning(p, "'*' interpreted as argument prefix");
h2so5's avatar
h2so5 committed
4339
        c = tSTAR;
mimaki's avatar
mimaki committed
4340 4341
      }
      else if (IS_BEG()) {
h2so5's avatar
h2so5 committed
4342
        c = tSTAR;
mimaki's avatar
mimaki committed
4343 4344
      }
      else {
h2so5's avatar
h2so5 committed
4345
        c = '*';
mimaki's avatar
mimaki committed
4346 4347
      }
    }
4348 4349
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4350 4351
    }
    else {
4352
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
4353 4354 4355 4356 4357 4358 4359 4360
    }
    return c;

  case '!':
    c = nextc(p);
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
      if (c == '@') {
h2so5's avatar
h2so5 committed
4361
        return '!';
mimaki's avatar
mimaki committed
4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377
      }
    }
    else {
      p->lstate = EXPR_BEG;
    }
    if (c == '=') {
      return tNEQ;
    }
    if (c == '~') {
      return tNMATCH;
    }
    pushback(p, c);
    return '!';

  case '=':
    if (p->column == 1) {
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
4378 4379 4380 4381
      static const char begin[] = "begin";
      static const char end[] = "\n=end";
      if (peeks(p, begin)) {
        c = peekc_n(p, sizeof(begin)-1);
cremno's avatar
cremno committed
4382
        if (c < 0 || ISSPACE(c)) {
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
4383 4384 4385 4386 4387
          do {
            if (!skips(p, end)) {
              yyerror(p, "embedded document meets end of file");
              return 0;
            }
Nobuyoshi Nakada's avatar
Nobuyoshi Nakada committed
4388
            c = nextc(p);
cremno's avatar
cremno committed
4389
          } while (!(c < 0 || ISSPACE(c)));
4390 4391 4392
          if (c != '\n') skip(p, '\n');
          p->lineno++;
          p->column = 0;
4393 4394
          goto retry;
        }
mimaki's avatar
mimaki committed
4395 4396
      }
    }
4397 4398
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4399 4400
    }
    else {
4401
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
4402 4403 4404
    }
    if ((c = nextc(p)) == '=') {
      if ((c = nextc(p)) == '=') {
h2so5's avatar
h2so5 committed
4405
        return tEQQ;
mimaki's avatar
mimaki committed
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421
      }
      pushback(p, c);
      return tEQ;
    }
    if (c == '~') {
      return tMATCH;
    }
    else if (c == '>') {
      return tASSOC;
    }
    pushback(p, c);
    return '=';

  case '<':
    c = nextc(p);
    if (c == '<' &&
h2so5's avatar
h2so5 committed
4422 4423 4424 4425
        p->lstate != EXPR_DOT &&
        p->lstate != EXPR_CLASS &&
        !IS_END() &&
        (!IS_ARG() || space_seen)) {
4426 4427
      int token = heredoc_identifier(p);
      if (token)
h2so5's avatar
h2so5 committed
4428
        return token;
mimaki's avatar
mimaki committed
4429
    }
4430 4431
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4432 4433
    }
    else {
4434 4435
      p->lstate = EXPR_BEG;
      if (p->lstate == EXPR_CLASS) {
h2so5's avatar
h2so5 committed
4436
        p->cmd_start = TRUE;
4437
      }
mimaki's avatar
mimaki committed
4438 4439 4440
    }
    if (c == '=') {
      if ((c = nextc(p)) == '>') {
h2so5's avatar
h2so5 committed
4441
        return tCMP;
mimaki's avatar
mimaki committed
4442 4443 4444 4445 4446 4447
      }
      pushback(p, c);
      return tLEQ;
    }
    if (c == '<') {
      if ((c = nextc(p)) == '=') {
4448
        pylval.id = intern("<<",2);
h2so5's avatar
h2so5 committed
4449 4450
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4451 4452 4453 4454 4455 4456 4457 4458
      }
      pushback(p, c);
      return tLSHFT;
    }
    pushback(p, c);
    return '<';

  case '>':
4459 4460
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4461 4462
    }
    else {
4463
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
4464 4465 4466 4467 4468 4469
    }
    if ((c = nextc(p)) == '=') {
      return tGEQ;
    }
    if (c == '>') {
      if ((c = nextc(p)) == '=') {
4470
        pylval.id = intern(">>",2);
h2so5's avatar
h2so5 committed
4471 4472
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4473 4474 4475 4476 4477 4478 4479 4480
      }
      pushback(p, c);
      return tRSHFT;
    }
    pushback(p, c);
    return '>';

  case '"':
4481
    p->lex_strterm = new_strterm(p, str_dquote, '"', 0);
mimaki's avatar
mimaki committed
4482 4483 4484
    return tSTRING_BEG;

  case '\'':
4485 4486
    p->lex_strterm = new_strterm(p, str_squote, '\'', 0);
    return parse_string(p);
mimaki's avatar
mimaki committed
4487

mattn's avatar
mattn committed
4488
  case '`':
4489 4490 4491 4492 4493 4494
    if (p->lstate == EXPR_FNAME) {
      p->lstate = EXPR_ENDFN;
      return '`';
    }
    if (p->lstate == EXPR_DOT) {
      if (cmd_state)
h2so5's avatar
h2so5 committed
4495
        p->lstate = EXPR_CMDARG;
4496
      else
h2so5's avatar
h2so5 committed
4497
        p->lstate = EXPR_ARG;
4498 4499
      return '`';
    }
mattn's avatar
mattn committed
4500 4501 4502
    p->lex_strterm = new_strterm(p, str_xquote, '`', 0);
    return tXSTRING_BEG;

mimaki's avatar
mimaki committed
4503 4504 4505 4506 4507 4508
  case '?':
    if (IS_END()) {
      p->lstate = EXPR_VALUE;
      return '?';
    }
    c = nextc(p);
4509
    if (c < 0) {
mimaki's avatar
mimaki committed
4510 4511 4512
      yyerror(p, "incomplete character syntax");
      return 0;
    }
cremno's avatar
cremno committed
4513
    if (ISSPACE(c)) {
mimaki's avatar
mimaki committed
4514
      if (!IS_ARG()) {
h2so5's avatar
h2so5 committed
4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543
        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);
        }
mimaki's avatar
mimaki committed
4544
      }
h2so5's avatar
h2so5 committed
4545
      ternary:
mimaki's avatar
mimaki committed
4546 4547 4548 4549
      pushback(p, c);
      p->lstate = EXPR_VALUE;
      return '?';
    }
4550
    newtok(p);
4551
    /* need support UTF-8 if configured */
mimaki's avatar
mimaki committed
4552 4553 4554 4555
    if ((isalnum(c) || c == '_')) {
      int c2 = nextc(p);
      pushback(p, c2);
      if ((isalnum(c2) || c2 == '_')) {
h2so5's avatar
h2so5 committed
4556
        goto ternary;
mimaki's avatar
mimaki committed
4557 4558 4559
      }
    }
    if (c == '\\') {
4560 4561
      c = read_escape(p);
      tokadd(p, c);
mimaki's avatar
mimaki committed
4562 4563 4564 4565 4566
    }
    else {
      tokadd(p, c);
    }
    tokfix(p);
4567
    pylval.nd = new_str(p, tok(p), toklen(p));
mimaki's avatar
mimaki committed
4568 4569 4570 4571 4572 4573 4574
    p->lstate = EXPR_END;
    return tCHAR;

  case '&':
    if ((c = nextc(p)) == '&') {
      p->lstate = EXPR_BEG;
      if ((c = nextc(p)) == '=') {
4575
        pylval.id = intern("&&",2);
h2so5's avatar
h2so5 committed
4576 4577
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4578 4579 4580 4581
      }
      pushback(p, c);
      return tANDOP;
    }
4582 4583 4584 4585
    else if (c == '.') {
      p->lstate = EXPR_DOT;
      return tANDDOT;
    }
mimaki's avatar
mimaki committed
4586
    else if (c == '=') {
4587
      pylval.id = intern_c('&');
mimaki's avatar
mimaki committed
4588 4589 4590 4591 4592
      p->lstate = EXPR_BEG;
      return tOP_ASGN;
    }
    pushback(p, c);
    if (IS_SPCARG(c)) {
4593
      yywarning(p, "'&' interpreted as argument prefix");
mimaki's avatar
mimaki committed
4594 4595 4596 4597 4598 4599 4600 4601
      c = tAMPER;
    }
    else if (IS_BEG()) {
      c = tAMPER;
    }
    else {
      c = '&';
    }
4602 4603
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4604 4605
    }
    else {
mimaki's avatar
mimaki committed
4606 4607 4608 4609 4610 4611 4612 4613
      p->lstate = EXPR_BEG;
    }
    return c;

  case '|':
    if ((c = nextc(p)) == '|') {
      p->lstate = EXPR_BEG;
      if ((c = nextc(p)) == '=') {
4614
        pylval.id = intern("||",2);
h2so5's avatar
h2so5 committed
4615 4616
        p->lstate = EXPR_BEG;
        return tOP_ASGN;
mimaki's avatar
mimaki committed
4617 4618 4619 4620 4621
      }
      pushback(p, c);
      return tOROP;
    }
    if (c == '=') {
4622
      pylval.id = intern_c('|');
mimaki's avatar
mimaki committed
4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639
      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 == '@') {
h2so5's avatar
h2so5 committed
4640
        return tUPLUS;
mimaki's avatar
mimaki committed
4641 4642 4643 4644 4645
      }
      pushback(p, c);
      return '+';
    }
    if (c == '=') {
4646
      pylval.id = intern_c('+');
mimaki's avatar
mimaki committed
4647 4648 4649 4650 4651 4652
      p->lstate = EXPR_BEG;
      return tOP_ASGN;
    }
    if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
      p->lstate = EXPR_BEG;
      pushback(p, c);
4653
      if (c >= 0 && ISDIGIT(c)) {
h2so5's avatar
h2so5 committed
4654 4655
        c = '+';
        goto start_num;
mimaki's avatar
mimaki committed
4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667
      }
      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 == '@') {
h2so5's avatar
h2so5 committed
4668
        return tUMINUS;
mimaki's avatar
mimaki committed
4669 4670 4671 4672 4673
      }
      pushback(p, c);
      return '-';
    }
    if (c == '=') {
4674
      pylval.id = intern_c('-');
mimaki's avatar
mimaki committed
4675 4676 4677 4678
      p->lstate = EXPR_BEG;
      return tOP_ASGN;
    }
    if (c == '>') {
4679
      p->lstate = EXPR_ENDFN;
mimaki's avatar
mimaki committed
4680 4681 4682 4683 4684
      return tLAMBDA;
    }
    if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
      p->lstate = EXPR_BEG;
      pushback(p, c);
4685
      if (c >= 0 && ISDIGIT(c)) {
h2so5's avatar
h2so5 committed
4686
        return tUMINUS_NUM;
mimaki's avatar
mimaki committed
4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697
      }
      return tUMINUS;
    }
    p->lstate = EXPR_BEG;
    pushback(p, c);
    return '-';

  case '.':
    p->lstate = EXPR_BEG;
    if ((c = nextc(p)) == '.') {
      if ((c = nextc(p)) == '.') {
h2so5's avatar
h2so5 committed
4698
        return tDOT3;
mimaki's avatar
mimaki committed
4699 4700 4701 4702 4703
      }
      pushback(p, c);
      return tDOT2;
    }
    pushback(p, c);
4704
    if (c >= 0 && ISDIGIT(c)) {
mimaki's avatar
mimaki committed
4705 4706 4707 4708 4709
      yyerror(p, "no .<digit> floating literal anymore; put 0 before dot");
    }
    p->lstate = EXPR_DOT;
    return '.';

h2so5's avatar
h2so5 committed
4710
    start_num:
mimaki's avatar
mimaki committed
4711 4712
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
h2so5's avatar
h2so5 committed
4713 4714
  {
    int is_float, seen_point, seen_e, nondigit;
kano4's avatar
kano4 committed
4715

h2so5's avatar
h2so5 committed
4716 4717
    is_float = seen_point = seen_e = nondigit = 0;
    p->lstate = EXPR_END;
4718
    newtok(p);
h2so5's avatar
h2so5 committed
4719 4720 4721 4722 4723
    if (c == '-' || c == '+') {
      tokadd(p, c);
      c = nextc(p);
    }
    if (c == '0') {
mimaki's avatar
mimaki committed
4724
#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0)
h2so5's avatar
h2so5 committed
4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747
      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;
4748
        pylval.nd = new_int(p, tok(p), 16);
h2so5's avatar
h2so5 committed
4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771
        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;
4772
        pylval.nd = new_int(p, tok(p), 2);
h2so5's avatar
h2so5 committed
4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795
        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;
4796
        pylval.nd = new_int(p, tok(p), 10);
h2so5's avatar
h2so5 committed
4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828
        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;
4829
          pylval.nd = new_int(p, tok(p), 8);
h2so5's avatar
h2so5 committed
4830 4831 4832 4833 4834 4835
          return tINTEGER;
        }
        if (nondigit) {
          pushback(p, c);
          goto trailing_uc;
        }
mimaki's avatar
mimaki committed
4836
      }
h2so5's avatar
h2so5 committed
4837 4838 4839 4840 4841 4842 4843 4844 4845
      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);
4846
        pylval.nd = new_int(p, "0", 10);
h2so5's avatar
h2so5 committed
4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898
        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;

4899
      case '_':       /* '_' in number just ignored */
h2so5's avatar
h2so5 committed
4900 4901 4902
        if (nondigit) goto decode_num;
        nondigit = c;
        break;
mimaki's avatar
mimaki committed
4903

h2so5's avatar
h2so5 committed
4904 4905
      default:
        goto decode_num;
mimaki's avatar
mimaki committed
4906
      }
h2so5's avatar
h2so5 committed
4907 4908
      c = nextc(p);
    }
mimaki's avatar
mimaki committed
4909 4910

    decode_num:
h2so5's avatar
h2so5 committed
4911 4912
    pushback(p, c);
    if (nondigit) {
mimaki's avatar
mimaki committed
4913
      trailing_uc:
4914
      yyerror_i(p, "trailing '%c' in number", nondigit);
h2so5's avatar
h2so5 committed
4915 4916 4917 4918 4919 4920 4921
    }
    tokfix(p);
    if (is_float) {
      double d;
      char *endp;

      errno = 0;
4922
      d = mrb_float_read(tok(p), &endp);
h2so5's avatar
h2so5 committed
4923 4924
      if (d == 0 && endp == tok(p)) {
        yywarning_s(p, "corrupted float value %s", tok(p));
mimaki's avatar
mimaki committed
4925
      }
h2so5's avatar
h2so5 committed
4926 4927 4928
      else if (errno == ERANGE) {
        yywarning_s(p, "float %s out of range", tok(p));
        errno = 0;
mimaki's avatar
mimaki committed
4929
      }
4930
      pylval.nd = new_float(p, tok(p));
h2so5's avatar
h2so5 committed
4931
      return tFLOAT;
mimaki's avatar
mimaki committed
4932
    }
4933
    pylval.nd = new_int(p, tok(p), 10);
h2so5's avatar
h2so5 committed
4934 4935
    return tINTEGER;
  }
mimaki's avatar
mimaki committed
4936 4937 4938 4939

  case ')':
  case ']':
    p->paren_nest--;
cremno's avatar
cremno committed
4940
    /* fall through */
mimaki's avatar
mimaki committed
4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953
  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)) {
h2so5's avatar
h2so5 committed
4954 4955
        p->lstate = EXPR_BEG;
        return tCOLON3;
mimaki's avatar
mimaki committed
4956 4957 4958 4959 4960 4961 4962 4963 4964
      }
      p->lstate = EXPR_DOT;
      return tCOLON2;
    }
    if (IS_END() || ISSPACE(c)) {
      pushback(p, c);
      p->lstate = EXPR_BEG;
      return ':';
    }
4965
    pushback(p, c);
mimaki's avatar
mimaki committed
4966 4967 4968 4969 4970 4971 4972 4973 4974
    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)) == '=') {
4975
      pylval.id = intern_c('/');
mimaki's avatar
mimaki committed
4976 4977 4978 4979 4980 4981 4982 4983
      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;
    }
4984 4985
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
4986 4987
    }
    else {
4988
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
4989 4990 4991 4992 4993
    }
    return '/';

  case '^':
    if ((c = nextc(p)) == '=') {
4994
      pylval.id = intern_c('^');
mimaki's avatar
mimaki committed
4995 4996 4997
      p->lstate = EXPR_BEG;
      return tOP_ASGN;
    }
4998 4999
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
5000 5001
    }
    else {
5002
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
5003 5004 5005 5006 5007 5008 5009
    }
    pushback(p, c);
    return '^';

  case ';':
    p->lstate = EXPR_BEG;
    return ';';
kano4's avatar
kano4 committed
5010

mimaki's avatar
mimaki committed
5011 5012 5013 5014 5015 5016 5017
  case ',':
    p->lstate = EXPR_BEG;
    return ',';

  case '~':
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      if ((c = nextc(p)) != '@') {
h2so5's avatar
h2so5 committed
5018
        pushback(p, c);
mimaki's avatar
mimaki committed
5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044
      }
      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)) == ']') {
h2so5's avatar
h2so5 committed
5045 5046 5047 5048 5049
        if ((c = nextc(p)) == '=') {
          return tASET;
        }
        pushback(p, c);
        return tAREF;
mimaki's avatar
mimaki committed
5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087
      }
      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') {
5088
      p->lineno++;
5089
      p->column = 0;
mimaki's avatar
mimaki committed
5090 5091 5092 5093 5094 5095 5096 5097
      space_seen = 1;
      goto retry; /* skip \\n */
    }
    pushback(p, c);
    return '\\';

  case '%':
    if (IS_BEG()) {
5098
      int term;
mimaki's avatar
mimaki committed
5099 5100 5101
      int paren;

      c = nextc(p);
h2so5's avatar
h2so5 committed
5102
      quotation:
5103
      if (c < 0 || !ISALNUM(c)) {
h2so5's avatar
h2so5 committed
5104 5105
        term = c;
        c = 'Q';
mimaki's avatar
mimaki committed
5106 5107
      }
      else {
h2so5's avatar
h2so5 committed
5108 5109 5110 5111 5112
        term = nextc(p);
        if (isalnum(term)) {
          yyerror(p, "unknown type of %string");
          return 0;
        }
mimaki's avatar
mimaki committed
5113
      }
5114
      if (c < 0 || term < 0) {
h2so5's avatar
h2so5 committed
5115 5116
        yyerror(p, "unterminated quoted string meets end of file");
        return 0;
mimaki's avatar
mimaki committed
5117 5118 5119 5120 5121 5122 5123 5124 5125 5126
      }
      paren = term;
      if (term == '(') term = ')';
      else if (term == '[') term = ']';
      else if (term == '{') term = '}';
      else if (term == '<') term = '>';
      else paren = 0;

      switch (c) {
      case 'Q':
h2so5's avatar
h2so5 committed
5127 5128
        p->lex_strterm = new_strterm(p, str_dquote, term, paren);
        return tSTRING_BEG;
mimaki's avatar
mimaki committed
5129 5130

      case 'q':
h2so5's avatar
h2so5 committed
5131 5132
        p->lex_strterm = new_strterm(p, str_squote, term, paren);
        return parse_string(p);
mimaki's avatar
mimaki committed
5133 5134

      case 'W':
h2so5's avatar
h2so5 committed
5135 5136
        p->lex_strterm = new_strterm(p, str_dword, term, paren);
        return tWORDS_BEG;
mimaki's avatar
mimaki committed
5137 5138

      case 'w':
h2so5's avatar
h2so5 committed
5139 5140
        p->lex_strterm = new_strterm(p, str_sword, term, paren);
        return tWORDS_BEG;
mimaki's avatar
mimaki committed
5141

mattn's avatar
mattn committed
5142
      case 'x':
h2so5's avatar
h2so5 committed
5143 5144
        p->lex_strterm = new_strterm(p, str_xquote, term, paren);
        return tXSTRING_BEG;
mattn's avatar
mattn committed
5145

mimaki's avatar
mimaki committed
5146
      case 'r':
h2so5's avatar
h2so5 committed
5147 5148
        p->lex_strterm = new_strterm(p, str_regexp, term, paren);
        return tREGEXP_BEG;
mimaki's avatar
mimaki committed
5149 5150

      case 's':
h2so5's avatar
h2so5 committed
5151 5152
        p->lex_strterm = new_strterm(p, str_ssym, term, paren);
        return tSYMBEG;
mimaki's avatar
mimaki committed
5153

FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
5154
      case 'I':
h2so5's avatar
h2so5 committed
5155 5156
        p->lex_strterm = new_strterm(p, str_dsymbols, term, paren);
        return tSYMBOLS_BEG;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
5157 5158

      case 'i':
h2so5's avatar
h2so5 committed
5159 5160
        p->lex_strterm = new_strterm(p, str_ssymbols, term, paren);
        return tSYMBOLS_BEG;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
5161

mimaki's avatar
mimaki committed
5162
      default:
h2so5's avatar
h2so5 committed
5163 5164
        yyerror(p, "unknown type of %string");
        return 0;
mimaki's avatar
mimaki committed
5165 5166 5167
      }
    }
    if ((c = nextc(p)) == '=') {
5168
      pylval.id = intern_c('%');
mimaki's avatar
mimaki committed
5169 5170 5171 5172 5173 5174
      p->lstate = EXPR_BEG;
      return tOP_ASGN;
    }
    if (IS_SPCARG(c)) {
      goto quotation;
    }
5175 5176
    if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
      p->lstate = EXPR_ARG;
5177 5178
    }
    else {
5179
      p->lstate = EXPR_BEG;
mimaki's avatar
mimaki committed
5180 5181 5182 5183 5184 5185
    }
    pushback(p, c);
    return '%';

  case '$':
    p->lstate = EXPR_END;
5186
    token_column = newtok(p);
mimaki's avatar
mimaki committed
5187
    c = nextc(p);
5188
    if (c < 0) {
5189 5190 5191
      yyerror(p, "incomplete global variable syntax");
      return 0;
    }
mimaki's avatar
mimaki committed
5192
    switch (c) {
kano4's avatar
kano4 committed
5193
    case '_':     /* $_: last read line string */
mimaki's avatar
mimaki committed
5194
      c = nextc(p);
5195
      if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */
h2so5's avatar
h2so5 committed
5196 5197 5198
        tokadd(p, '$');
        tokadd(p, c);
        break;
5199
      }
mimaki's avatar
mimaki committed
5200 5201 5202
      pushback(p, c);
      c = '_';
      /* fall through */
kano4's avatar
kano4 committed
5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218
    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 */
mimaki's avatar
mimaki committed
5219 5220 5221
      tokadd(p, '$');
      tokadd(p, c);
      tokfix(p);
5222
      pylval.id = intern_cstr(tok(p));
mimaki's avatar
mimaki committed
5223 5224 5225 5226 5227 5228 5229
      return tGVAR;

    case '-':
      tokadd(p, '$');
      tokadd(p, c);
      c = nextc(p);
      pushback(p, c);
h2so5's avatar
h2so5 committed
5230
      gvar:
mimaki's avatar
mimaki committed
5231
      tokfix(p);
5232
      pylval.id = intern_cstr(tok(p));
mimaki's avatar
mimaki committed
5233 5234
      return tGVAR;

kano4's avatar
kano4 committed
5235 5236 5237 5238
    case '&':     /* $&: last match */
    case '`':     /* $`: string before last match */
    case '\'':    /* $': string after last match */
    case '+':     /* $+: string matches last pattern */
mimaki's avatar
mimaki committed
5239
      if (last_state == EXPR_FNAME) {
h2so5's avatar
h2so5 committed
5240 5241 5242
        tokadd(p, '$');
        tokadd(p, c);
        goto gvar;
mimaki's avatar
mimaki committed
5243
      }
5244
      pylval.nd = new_back_ref(p, c);
mimaki's avatar
mimaki committed
5245 5246 5247 5248 5249 5250
      return tBACK_REF;

    case '1': case '2': case '3':
    case '4': case '5': case '6':
    case '7': case '8': case '9':
      do {
h2so5's avatar
h2so5 committed
5251 5252
        tokadd(p, c);
        c = nextc(p);
5253
      } while (c >= 0 && isdigit(c));
mimaki's avatar
mimaki committed
5254 5255 5256
      pushback(p, c);
      if (last_state == EXPR_FNAME) goto gvar;
      tokfix(p);
cremno's avatar
cremno committed
5257 5258 5259 5260 5261 5262
      {
        unsigned long n = strtoul(tok(p), NULL, 10);
        if (n > INT_MAX) {
          yyerror_i(p, "capture group index must be <= %d", INT_MAX);
          return 0;
        }
5263
        pylval.nd = new_nth_ref(p, (int)n);
cremno's avatar
cremno committed
5264
      }
mimaki's avatar
mimaki committed
5265 5266 5267 5268
      return tNTH_REF;

    default:
      if (!identchar(c)) {
h2so5's avatar
h2so5 committed
5269 5270
        pushback(p,  c);
        return '$';
mimaki's avatar
mimaki committed
5271
      }
cremno's avatar
cremno committed
5272
      /* fall through */
mimaki's avatar
mimaki committed
5273 5274 5275 5276 5277
    case '0':
      tokadd(p, '$');
    }
    break;

h2so5's avatar
h2so5 committed
5278
    case '@':
mimaki's avatar
mimaki committed
5279
      c = nextc(p);
h2so5's avatar
h2so5 committed
5280 5281 5282 5283 5284
      token_column = newtok(p);
      tokadd(p, '@');
      if (c == '@') {
        tokadd(p, '@');
        c = nextc(p);
5285
      }
h2so5's avatar
h2so5 committed
5286
      if (c < 0) {
5287
        if (p->tidx == 1) {
h2so5's avatar
h2so5 committed
5288 5289 5290 5291 5292 5293
          yyerror(p, "incomplete instance variable syntax");
        }
        else {
          yyerror(p, "incomplete class variable syntax");
        }
        return 0;
5294
      }
h2so5's avatar
h2so5 committed
5295
      else if (isdigit(c)) {
5296
        if (p->tidx == 1) {
5297
          yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
h2so5's avatar
h2so5 committed
5298 5299
        }
        else {
5300
          yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
h2so5's avatar
h2so5 committed
5301 5302
        }
        return 0;
mimaki's avatar
mimaki committed
5303
      }
h2so5's avatar
h2so5 committed
5304 5305 5306
      if (!identchar(c)) {
        pushback(p, c);
        return '@';
mimaki's avatar
mimaki committed
5307
      }
h2so5's avatar
h2so5 committed
5308
      break;
mimaki's avatar
mimaki committed
5309

h2so5's avatar
h2so5 committed
5310 5311 5312
    case '_':
      token_column = newtok(p);
      break;
mimaki's avatar
mimaki committed
5313

h2so5's avatar
h2so5 committed
5314 5315
    default:
      if (!identchar(c)) {
5316
        yyerror_i(p,  "Invalid char '\\x%02X' in expression", c);
h2so5's avatar
h2so5 committed
5317 5318
        goto retry;
      }
mimaki's avatar
mimaki committed
5319

h2so5's avatar
h2so5 committed
5320 5321
      token_column = newtok(p);
      break;
mimaki's avatar
mimaki committed
5322 5323 5324 5325 5326 5327 5328
  }

  do {
    tokadd(p, c);
    c = nextc(p);
    if (c < 0) break;
  } while (identchar(c));
5329 5330
  if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') &&
      strncmp(tok(p), "__END__", toklen(p)) == 0)
5331
    return -1;
mimaki's avatar
mimaki committed
5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356

  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] == '@')
h2so5's avatar
h2so5 committed
5357
        result = tCVAR;
mimaki's avatar
mimaki committed
5358
      else
h2so5's avatar
h2so5 committed
5359
        result = tIVAR;
mimaki's avatar
mimaki committed
5360 5361 5362 5363
      break;

    default:
      if (toklast(p) == '!' || toklast(p) == '?') {
h2so5's avatar
h2so5 committed
5364
        result = tFID;
mimaki's avatar
mimaki committed
5365 5366
      }
      else {
h2so5's avatar
h2so5 committed
5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377
        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);
          }
        }
cremno's avatar
cremno committed
5378
        if (result == 0 && ISUPPER(tok(p)[0])) {
h2so5's avatar
h2so5 committed
5379 5380 5381 5382 5383
          result = tCONSTANT;
        }
        else {
          result = tIDENTIFIER;
        }
mimaki's avatar
mimaki committed
5384 5385 5386
      }

      if (IS_LABEL_POSSIBLE()) {
h2so5's avatar
h2so5 committed
5387 5388 5389 5390
        if (IS_LABEL_SUFFIX(0)) {
          p->lstate = EXPR_BEG;
          nextc(p);
          tokfix(p);
5391
          pylval.id = intern_cstr(tok(p));
h2so5's avatar
h2so5 committed
5392 5393
          return tLABEL;
        }
mimaki's avatar
mimaki committed
5394 5395
      }
      if (p->lstate != EXPR_DOT) {
h2so5's avatar
h2so5 committed
5396 5397 5398 5399 5400 5401
        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;
5402
          pylval.num = p->lineno;
h2so5's avatar
h2so5 committed
5403 5404
          p->lstate = kw->state;
          if (state == EXPR_FNAME) {
5405
            pylval.id = intern_cstr(kw->name);
h2so5's avatar
h2so5 committed
5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431
            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];
          }
        }
mimaki's avatar
mimaki committed
5432 5433
      }

kano4's avatar
kano4 committed
5434
      if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) {
h2so5's avatar
h2so5 committed
5435 5436 5437 5438 5439 5440
        if (cmd_state) {
          p->lstate = EXPR_CMDARG;
        }
        else {
          p->lstate = EXPR_ARG;
        }
mimaki's avatar
mimaki committed
5441 5442
      }
      else if (p->lstate == EXPR_FNAME) {
h2so5's avatar
h2so5 committed
5443
        p->lstate = EXPR_ENDFN;
mimaki's avatar
mimaki committed
5444 5445
      }
      else {
h2so5's avatar
h2so5 committed
5446
        p->lstate = EXPR_END;
mimaki's avatar
mimaki committed
5447 5448 5449
      }
    }
    {
5450
      mrb_sym ident = intern_cstr(tok(p));
mimaki's avatar
mimaki committed
5451

5452
      pylval.id = ident;
mimaki's avatar
mimaki committed
5453 5454
#if 0
      if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
h2so5's avatar
h2so5 committed
5455
        p->lstate = EXPR_END;
mimaki's avatar
mimaki committed
5456 5457 5458 5459 5460 5461 5462 5463 5464 5465
      }
#endif
    }
    return result;
  }
}

static int
yylex(void *lval, parser_state *p)
{
kano4's avatar
kano4 committed
5466
  p->ylval = lval;
Jun Hiroe's avatar
Jun Hiroe committed
5467
  return parser_yylex(p);
mimaki's avatar
mimaki committed
5468 5469
}

5470 5471 5472
static void
parser_init_cxt(parser_state *p, mrbc_context *cxt)
{
5473
  if (!cxt) return;
5474
  if (cxt->filename) mrb_parser_set_filename(p, cxt->filename);
5475
  if (cxt->lineno) p->lineno = cxt->lineno;
5476
  if (cxt->syms) {
5477
    int i;
5478 5479

    p->locals = cons(0,0);
5480 5481
    for (i=0; i<cxt->slen; i++) {
      local_add_f(p, cxt->syms[i]);
5482 5483
    }
  }
5484
  p->capture_errors = cxt->capture_errors;
5485
  p->no_optimize = cxt->no_optimize;
5486 5487 5488
  if (cxt->partial_hook) {
    p->cxt = cxt;
  }
5489 5490 5491 5492 5493 5494 5495 5496 5497
}

static void
parser_update_cxt(parser_state *p, mrbc_context *cxt)
{
  node *n, *n0;
  int i = 0;

  if (!cxt) return;
5498
  if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return;
5499 5500 5501 5502 5503
  n0 = n = p->tree->cdr->car;
  while (n) {
    i++;
    n = n->cdr;
  }
Max Anselm's avatar
Max Anselm committed
5504
  cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym));
5505 5506
  cxt->slen = i;
  for (i=0, n=n0; n; i++,n=n->cdr) {
5507
    cxt->syms[i] = sym(n->car);
5508 5509 5510
  }
}

cremno's avatar
cremno committed
5511 5512
void mrb_codedump_all(mrb_state*, struct RProc*);
void mrb_parser_dump(mrb_state *mrb, node *tree, int offset);
5513

5514
MRB_API void
5515
mrb_parser_parse(parser_state *p, mrbc_context *c)
mimaki's avatar
mimaki committed
5516
{
5517 5518
  struct mrb_jmpbuf buf1;
  p->jmp = &buf1;
take_cheeze's avatar
take_cheeze committed
5519 5520

  MRB_TRY(p->jmp) {
5521
    int n;
5522

yui-knk's avatar
yui-knk committed
5523 5524 5525 5526
    p->cmd_start = TRUE;
    p->in_def = p->in_single = 0;
    p->nerr = p->nwarn = 0;
    p->lex_strterm = NULL;
5527

yui-knk's avatar
yui-knk committed
5528
    parser_init_cxt(p, c);
5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547

    if (p->mrb->jmp) {
      n = yyparse(p);
    }
    else {
      struct mrb_jmpbuf buf2;

      p->mrb->jmp = &buf2;
      MRB_TRY(p->mrb->jmp) {
        n = yyparse(p);
      }
      MRB_CATCH(p->mrb->jmp) {
        p->nerr++;
        mrb_p(p->mrb, mrb_obj_value(p->mrb->exc));
      }
      MRB_END_EXC(p->mrb->jmp);
      p->mrb->jmp = 0;
    }
    if (n != 0 || p->nerr > 0) {
5548 5549 5550
      p->tree = 0;
      return;
    }
yui-knk's avatar
yui-knk committed
5551 5552 5553 5554 5555 5556 5557
    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);
    }
take_cheeze's avatar
take_cheeze committed
5558 5559 5560 5561 5562 5563 5564 5565
  }
  MRB_CATCH(p->jmp) {
    yyerror(p, "memory allocation error");
    p->nerr++;
    p->tree = 0;
    return;
  }
  MRB_END_EXC(p->jmp);
mimaki's avatar
mimaki committed
5566 5567
}

5568
MRB_API parser_state*
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5569
mrb_parser_new(mrb_state *mrb)
mimaki's avatar
mimaki committed
5570 5571 5572
{
  mrb_pool *pool;
  parser_state *p;
5573
  static const parser_state parser_state_zero = { 0 };
mimaki's avatar
mimaki committed
5574 5575

  pool = mrb_pool_open(mrb);
5576
  if (!pool) return NULL;
Max Anselm's avatar
Max Anselm committed
5577
  p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state));
5578
  if (!p) return NULL;
mimaki's avatar
mimaki committed
5579

5580
  *p = parser_state_zero;
mimaki's avatar
mimaki committed
5581 5582 5583
  p->mrb = mrb;
  p->pool = pool;

Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5584
  p->s = p->send = NULL;
5585
#ifndef MRB_DISABLE_STDIO
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5586
  p->f = NULL;
5587
#endif
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5588

mimaki's avatar
mimaki committed
5589
  p->cmd_start = TRUE;
cremno's avatar
cremno committed
5590
  p->in_def = p->in_single = 0;
mimaki's avatar
mimaki committed
5591

cremno's avatar
cremno committed
5592
  p->capture_errors = FALSE;
mimaki's avatar
mimaki committed
5593
  p->lineno = 1;
5594
  p->column = 0;
mimaki's avatar
mimaki committed
5595 5596 5597
#if defined(PARSER_TEST) || defined(PARSER_DEBUG)
  yydebug = 1;
#endif
5598 5599
  p->tsiz = MRB_PARSER_TOKBUF_SIZE;
  p->tokbuf = p->buf;
mimaki's avatar
mimaki committed
5600

5601
  p->lex_strterm = NULL;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
5602 5603
  p->all_heredocs = p->parsing_heredoc = NULL;
  p->lex_strterm_before_heredoc = NULL;
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
5604

5605 5606 5607 5608
  p->current_filename_index = -1;
  p->filename_table = NULL;
  p->filename_table_length = 0;

mimaki's avatar
mimaki committed
5609 5610 5611
  return p;
}

5612
MRB_API void
5613
mrb_parser_free(parser_state *p) {
5614 5615 5616
  if (p->tokbuf != p->buf) {
    mrb_free(p->mrb, p->tokbuf);
  }
5617
  mrb_pool_close(p->pool);
5618 5619
}

5620
MRB_API mrbc_context*
5621 5622
mrbc_context_new(mrb_state *mrb)
{
Jun Hiroe's avatar
Jun Hiroe committed
5623
  return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context));
5624 5625
}

5626
MRB_API void
5627 5628
mrbc_context_free(mrb_state *mrb, mrbc_context *cxt)
{
5629
  mrb_free(mrb, cxt->filename);
5630 5631 5632 5633
  mrb_free(mrb, cxt->syms);
  mrb_free(mrb, cxt);
}

5634
MRB_API const char*
5635
mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s)
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5636 5637
{
  if (s) {
5638
    int len = strlen(s);
5639
    char *p = (char *)mrb_malloc(mrb, len + 1);
5640

5641
    memcpy(p, s, len + 1);
5642 5643 5644
    if (c->filename) {
      mrb_free(mrb, c->filename);
    }
5645
    c->filename = p;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5646
  }
5647
  return c->filename;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5648 5649
}

5650
MRB_API void
5651 5652 5653 5654 5655 5656
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;
}

5657
MRB_API void
5658
mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
5659
{
5660 5661 5662 5663 5664
  mrb_sym sym;
  size_t i;
  mrb_sym* new_table;

  sym = mrb_intern_cstr(p->mrb, f);
5665
  p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
5666
  p->lineno = (p->filename_table_length > 0)? 0 : 1;
cremno's avatar
cremno committed
5667

5668 5669
  for (i = 0; i < p->filename_table_length; ++i) {
    if (p->filename_table[i] == sym) {
take_cheeze's avatar
take_cheeze committed
5670 5671 5672 5673 5674 5675 5676
      p->current_filename_index = i;
      return;
    }
  }

  p->current_filename_index = p->filename_table_length++;

take_cheeze's avatar
take_cheeze committed
5677
  new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
take_cheeze's avatar
take_cheeze committed
5678
  if (p->filename_table) {
cremno's avatar
cremno committed
5679
    memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
take_cheeze's avatar
take_cheeze committed
5680 5681 5682 5683 5684
  }
  p->filename_table = new_table;
  p->filename_table[p->filename_table_length - 1] = sym;
}

5685
MRB_API char const*
Jun Hiroe's avatar
Jun Hiroe committed
5686
mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
take_cheeze's avatar
take_cheeze committed
5687 5688
  if (idx >= p->filename_table_length) { return NULL; }
  else {
5689
    return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
take_cheeze's avatar
take_cheeze committed
5690
  }
5691 5692
}

5693
#ifndef MRB_DISABLE_STDIO
5694
MRB_API parser_state*
5695
mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
mimaki's avatar
mimaki committed
5696 5697
{
  parser_state *p;
fleuria's avatar
fleuria committed
5698

Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5699
  p = mrb_parser_new(mrb);
5700
  if (!p) return NULL;
mimaki's avatar
mimaki committed
5701 5702 5703
  p->s = p->send = NULL;
  p->f = f;

5704
  mrb_parser_parse(p, c);
mimaki's avatar
mimaki committed
5705 5706
  return p;
}
5707
#endif
mimaki's avatar
mimaki committed
5708

5709
MRB_API parser_state*
5710
mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c)
mimaki's avatar
mimaki committed
5711 5712 5713
{
  parser_state *p;

Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
5714
  p = mrb_parser_new(mrb);
5715
  if (!p) return NULL;
5716
  p->s = s;
mimaki's avatar
mimaki committed
5717 5718
  p->send = s + len;

5719
  mrb_parser_parse(p, c);
mimaki's avatar
mimaki committed
5720 5721 5722
  return p;
}

5723
MRB_API parser_state*
5724
mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c)
mimaki's avatar
mimaki committed
5725
{
5726
  return mrb_parse_nstring(mrb, s, strlen(s), c);
mimaki's avatar
mimaki committed
5727 5728
}

5729 5730
MRB_API mrb_value
mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
mimaki's avatar
mimaki committed
5731
{
5732 5733
  struct RClass *target = mrb->object_class;
  struct RProc *proc;
5734
  mrb_value v;
5735
  unsigned int keep = 0;
mimaki's avatar
mimaki committed
5736

5737
  if (!p) {
5738
    return mrb_undef_value();
5739
  }
5740 5741 5742
  if (!p->tree || p->nerr) {
    if (p->capture_errors) {
      char buf[256];
5743
      int n;
5744

5745
      n = snprintf(buf, sizeof(buf), "line %d: %s\n",
h2so5's avatar
h2so5 committed
5746
          p->error_buffer[0].lineno, p->error_buffer[0].message);
5747
      mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
5748 5749
      mrb_parser_free(p);
      return mrb_undef_value();
5750 5751
    }
    else {
cubicdaiya's avatar
cubicdaiya committed
5752
      mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
5753
      mrb_parser_free(p);
5754
      return mrb_undef_value();
5755
    }
5756
  }
5757
  proc = mrb_generate_code(mrb, p);
5758
  mrb_parser_free(p);
5759
  if (proc == NULL) {
cubicdaiya's avatar
cubicdaiya committed
5760
    mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
5761
    return mrb_undef_value();
5762
  }
5763
  if (c) {
cremno's avatar
cremno committed
5764
    if (c->dump_result) mrb_codedump_all(mrb, proc);
5765
    if (c->no_exec) return mrb_obj_value(proc);
5766 5767 5768
    if (c->target_class) {
      target = c->target_class;
    }
5769 5770 5771 5772 5773 5774
    if (c->keep_lv) {
      keep = c->slen + 1;
    }
    else {
      c->keep_lv = TRUE;
    }
5775
  }
5776
  proc->target_class = target;
5777 5778 5779
  if (mrb->c->ci) {
    mrb->c->ci->target_class = target;
  }
5780
  v = mrb_top_run(mrb, proc, mrb_top_self(mrb), keep);
5781
  if (mrb->exc) return mrb_nil_value();
5782
  return v;
mimaki's avatar
mimaki committed
5783 5784
}

5785
#ifndef MRB_DISABLE_STDIO
5786
MRB_API mrb_value
5787 5788
mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c)
{
5789
  return mrb_load_exec(mrb, mrb_parse_file(mrb, f, c), c);
5790 5791
}

5792
MRB_API mrb_value
5793
mrb_load_file(mrb_state *mrb, FILE *f)
mimaki's avatar
mimaki committed
5794
{
5795 5796
  return mrb_load_file_cxt(mrb, f, NULL);
}
5797
#endif
5798

5799
MRB_API mrb_value
5800 5801
mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
{
5802
  return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
5803
}
mimaki's avatar
mimaki committed
5804

5805
MRB_API mrb_value
5806 5807
mrb_load_nstring(mrb_state *mrb, const char *s, int len)
{
5808 5809 5810
  return mrb_load_nstring_cxt(mrb, s, len, NULL);
}

5811
MRB_API mrb_value
5812 5813
mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c)
{
5814
  return mrb_load_nstring_cxt(mrb, s, strlen(s), c);
mimaki's avatar
mimaki committed
5815 5816
}

5817
MRB_API mrb_value
5818
mrb_load_string(mrb_state *mrb, const char *s)
mimaki's avatar
mimaki committed
5819
{
5820
  return mrb_load_string_cxt(mrb, s, NULL);
mimaki's avatar
mimaki committed
5821 5822
}

5823
#ifndef MRB_DISABLE_STDIO
5824

mimaki's avatar
mimaki committed
5825
static void
5826
dump_prefix(node *tree, int offset)
mimaki's avatar
mimaki committed
5827
{
5828
  printf("%05d ", tree->lineno);
mimaki's avatar
mimaki committed
5829 5830 5831 5832 5833 5834 5835 5836 5837 5838
  while (offset--) {
    putc(' ', stdout);
    putc(' ', stdout);
  }
}

static void
dump_recur(mrb_state *mrb, node *tree, int offset)
{
  while (tree) {
cremno's avatar
cremno committed
5839
    mrb_parser_dump(mrb, tree->car, offset);
mimaki's avatar
mimaki committed
5840 5841 5842 5843
    tree = tree->cdr;
  }
}

5844 5845
#endif

mimaki's avatar
mimaki committed
5846
void
cremno's avatar
cremno committed
5847
mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
mimaki's avatar
mimaki committed
5848
{
5849
#ifndef MRB_DISABLE_STDIO
5850
  int nodetype;
mimaki's avatar
mimaki committed
5851 5852

  if (!tree) return;
h2so5's avatar
h2so5 committed
5853
  again:
5854
  dump_prefix(tree, offset);
5855
  nodetype = (int)(intptr_t)tree->car;
mimaki's avatar
mimaki committed
5856
  tree = tree->cdr;
5857
  switch (nodetype) {
mimaki's avatar
mimaki committed
5858 5859 5860 5861 5862 5863 5864 5865
  case NODE_BEGIN:
    printf("NODE_BEGIN:\n");
    dump_recur(mrb, tree, offset+1);
    break;

  case NODE_RESCUE:
    printf("NODE_RESCUE:\n");
    if (tree->car) {
5866
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5867
      printf("body:\n");
cremno's avatar
cremno committed
5868
      mrb_parser_dump(mrb, tree->car, offset+2);
mimaki's avatar
mimaki committed
5869 5870 5871 5872 5873
    }
    tree = tree->cdr;
    if (tree->car) {
      node *n2 = tree->car;

5874
      dump_prefix(n2, offset+1);
mimaki's avatar
mimaki committed
5875 5876
      printf("rescue:\n");
      while (n2) {
h2so5's avatar
h2so5 committed
5877 5878
        node *n3 = n2->car;
        if (n3->car) {
5879
          dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
5880 5881 5882 5883
          printf("handle classes:\n");
          dump_recur(mrb, n3->car, offset+3);
        }
        if (n3->cdr->car) {
5884
          dump_prefix(n3, offset+2);
h2so5's avatar
h2so5 committed
5885
          printf("exc_var:\n");
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
5886
          mrb_parser_dump(mrb, n3->cdr->car, offset+3);
h2so5's avatar
h2so5 committed
5887 5888
        }
        if (n3->cdr->cdr->car) {
5889
          dump_prefix(n3, offset+2);
h2so5's avatar
h2so5 committed
5890
          printf("rescue body:\n");
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
5891
          mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3);
h2so5's avatar
h2so5 committed
5892 5893
        }
        n2 = n2->cdr;
mimaki's avatar
mimaki committed
5894 5895 5896 5897
      }
    }
    tree = tree->cdr;
    if (tree->car) {
5898
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5899
      printf("else:\n");
cremno's avatar
cremno committed
5900
      mrb_parser_dump(mrb, tree->car, offset+2);
mimaki's avatar
mimaki committed
5901 5902 5903 5904 5905
    }
    break;

  case NODE_ENSURE:
    printf("NODE_ENSURE:\n");
5906
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5907
    printf("body:\n");
cremno's avatar
cremno committed
5908
    mrb_parser_dump(mrb, tree->car, offset+2);
5909
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5910
    printf("ensure:\n");
cremno's avatar
cremno committed
5911
    mrb_parser_dump(mrb, tree->cdr->cdr, offset+2);
mimaki's avatar
mimaki committed
5912 5913 5914 5915 5916 5917 5918
    break;

  case NODE_LAMBDA:
    printf("NODE_BLOCK:\n");
    goto block;

  case NODE_BLOCK:
h2so5's avatar
h2so5 committed
5919
    block:
mimaki's avatar
mimaki committed
5920
    printf("NODE_BLOCK:\n");
5921 5922 5923
    tree = tree->cdr;
    if (tree->car) {
      node *n = tree->car;
mimaki's avatar
mimaki committed
5924

5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935
      if (n->car) {
        dump_prefix(n, offset+1);
        printf("mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
      }
      n = n->cdr;
      if (n->car) {
        dump_prefix(n, offset+1);
        printf("optional args:\n");
        {
          node *n2 = n->car;
h2so5's avatar
h2so5 committed
5936

5937 5938 5939 5940 5941 5942
          while (n2) {
            dump_prefix(n2, offset+2);
            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
            mrb_parser_dump(mrb, n2->car->cdr, 0);
            n2 = n2->cdr;
          }
h2so5's avatar
h2so5 committed
5943
        }
mimaki's avatar
mimaki committed
5944
      }
5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955
      n = n->cdr;
      if (n->car) {
        dump_prefix(n, offset+1);
        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
      }
      n = n->cdr;
      if (n->car) {
        dump_prefix(n, offset+1);
        printf("post mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
      }
5956
      if (n->cdr) {
5957
        dump_prefix(n, offset+1);
5958
        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
5959
      }
mimaki's avatar
mimaki committed
5960
    }
5961 5962 5963 5964
    dump_prefix(tree, offset+1);
    printf("body:\n");
    mrb_parser_dump(mrb, tree->cdr->car, offset+2);
    break;
mimaki's avatar
mimaki committed
5965 5966 5967

  case NODE_IF:
    printf("NODE_IF:\n");
5968
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5969
    printf("cond:\n");
cremno's avatar
cremno committed
5970
    mrb_parser_dump(mrb, tree->car, offset+2);
5971
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5972
    printf("then:\n");
cremno's avatar
cremno committed
5973
    mrb_parser_dump(mrb, tree->cdr->car, offset+2);
mimaki's avatar
mimaki committed
5974
    if (tree->cdr->cdr->car) {
5975
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
5976
      printf("else:\n");
cremno's avatar
cremno committed
5977
      mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2);
mimaki's avatar
mimaki committed
5978 5979 5980 5981 5982
    }
    break;

  case NODE_AND:
    printf("NODE_AND:\n");
cremno's avatar
cremno committed
5983 5984
    mrb_parser_dump(mrb, tree->car, offset+1);
    mrb_parser_dump(mrb, tree->cdr, offset+1);
mimaki's avatar
mimaki committed
5985 5986 5987 5988
    break;

  case NODE_OR:
    printf("NODE_OR:\n");
cremno's avatar
cremno committed
5989 5990
    mrb_parser_dump(mrb, tree->car, offset+1);
    mrb_parser_dump(mrb, tree->cdr, offset+1);
mimaki's avatar
mimaki committed
5991 5992 5993 5994 5995
    break;

  case NODE_CASE:
    printf("NODE_CASE:\n");
    if (tree->car) {
cremno's avatar
cremno committed
5996
      mrb_parser_dump(mrb, tree->car, offset+1);
mimaki's avatar
mimaki committed
5997 5998 5999
    }
    tree = tree->cdr;
    while (tree) {
6000
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6001 6002
      printf("case:\n");
      dump_recur(mrb, tree->car->car, offset+2);
6003
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6004
      printf("body:\n");
cremno's avatar
cremno committed
6005
      mrb_parser_dump(mrb, tree->car->cdr, offset+2);
mimaki's avatar
mimaki committed
6006 6007 6008 6009 6010 6011
      tree = tree->cdr;
    }
    break;

  case NODE_WHILE:
    printf("NODE_WHILE:\n");
6012
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6013
    printf("cond:\n");
cremno's avatar
cremno committed
6014
    mrb_parser_dump(mrb, tree->car, offset+2);
6015
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6016
    printf("body:\n");
cremno's avatar
cremno committed
6017
    mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6018 6019 6020 6021
    break;

  case NODE_UNTIL:
    printf("NODE_UNTIL:\n");
6022
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6023
    printf("cond:\n");
cremno's avatar
cremno committed
6024
    mrb_parser_dump(mrb, tree->car, offset+2);
6025
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6026
    printf("body:\n");
cremno's avatar
cremno committed
6027
    mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6028 6029 6030 6031
    break;

  case NODE_FOR:
    printf("NODE_FOR:\n");
6032
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6033 6034 6035 6036 6037
    printf("var:\n");
    {
      node *n2 = tree->car;

      if (n2->car) {
6038
        dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6039 6040
        printf("pre:\n");
        dump_recur(mrb, n2->car, offset+3);
mimaki's avatar
mimaki committed
6041 6042 6043
      }
      n2 = n2->cdr;
      if (n2) {
h2so5's avatar
h2so5 committed
6044
        if (n2->car) {
6045
          dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6046
          printf("rest:\n");
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6047
          mrb_parser_dump(mrb, n2->car, offset+3);
h2so5's avatar
h2so5 committed
6048 6049 6050 6051
        }
        n2 = n2->cdr;
        if (n2) {
          if (n2->car) {
6052
            dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6053 6054 6055 6056
            printf("post:\n");
            dump_recur(mrb, n2->car, offset+3);
          }
        }
mimaki's avatar
mimaki committed
6057 6058 6059
      }
    }
    tree = tree->cdr;
6060
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6061
    printf("in:\n");
cremno's avatar
cremno committed
6062
    mrb_parser_dump(mrb, tree->car, offset+2);
mimaki's avatar
mimaki committed
6063
    tree = tree->cdr;
6064
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6065
    printf("do:\n");
cremno's avatar
cremno committed
6066
    mrb_parser_dump(mrb, tree->car, offset+2);
mimaki's avatar
mimaki committed
6067 6068 6069 6070 6071 6072
    break;

  case NODE_SCOPE:
    printf("NODE_SCOPE:\n");
    {
      node *n2 = tree->car;
6073
      mrb_bool first_lval = TRUE;
mimaki's avatar
mimaki committed
6074

yui-knk's avatar
yui-knk committed
6075
      if (n2 && (n2->car || n2->cdr)) {
6076
        dump_prefix(n2, offset+1);
h2so5's avatar
h2so5 committed
6077
        printf("local variables:\n");
6078
        dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6079 6080
        while (n2) {
          if (n2->car) {
6081
            if (!first_lval) printf(", ");
h2so5's avatar
h2so5 committed
6082
            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
6083
            first_lval = FALSE;
h2so5's avatar
h2so5 committed
6084 6085 6086 6087
          }
          n2 = n2->cdr;
        }
        printf("\n");
mimaki's avatar
mimaki committed
6088 6089 6090 6091 6092 6093 6094 6095
      }
    }
    tree = tree->cdr;
    offset++;
    goto again;

  case NODE_FCALL:
  case NODE_CALL:
6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106
  case NODE_SCALL:
    switch (nodetype) {
    case NODE_FCALL:
      printf("NODE_FCALL:\n"); break;
    case NODE_CALL:
      printf("NODE_CALL(.):\n"); break;
    case NODE_SCALL:
      printf("NODE_SCALL(&.):\n"); break;
    default:
      break;
    }
cremno's avatar
cremno committed
6107
    mrb_parser_dump(mrb, tree->car, offset+1);
6108
    dump_prefix(tree, offset+1);
fleuria's avatar
fleuria committed
6109
    printf("method='%s' (%d)\n",
h2so5's avatar
h2so5 committed
6110 6111
        mrb_sym2name(mrb, sym(tree->cdr->car)),
        (int)(intptr_t)tree->cdr->car);
mimaki's avatar
mimaki committed
6112 6113
    tree = tree->cdr->cdr->car;
    if (tree) {
6114
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6115 6116 6117
      printf("args:\n");
      dump_recur(mrb, tree->car, offset+2);
      if (tree->cdr) {
6118
        dump_prefix(tree, offset+1);
h2so5's avatar
h2so5 committed
6119
        printf("block:\n");
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6120
        mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6121 6122 6123 6124 6125 6126
      }
    }
    break;

  case NODE_DOT2:
    printf("NODE_DOT2:\n");
cremno's avatar
cremno committed
6127 6128
    mrb_parser_dump(mrb, tree->car, offset+1);
    mrb_parser_dump(mrb, tree->cdr, offset+1);
mimaki's avatar
mimaki committed
6129 6130 6131 6132
    break;

  case NODE_DOT3:
    printf("NODE_DOT3:\n");
cremno's avatar
cremno committed
6133 6134
    mrb_parser_dump(mrb, tree->car, offset+1);
    mrb_parser_dump(mrb, tree->cdr, offset+1);
mimaki's avatar
mimaki committed
6135 6136 6137 6138
    break;

  case NODE_COLON2:
    printf("NODE_COLON2:\n");
cremno's avatar
cremno committed
6139
    mrb_parser_dump(mrb, tree->car, offset+1);
6140
    dump_prefix(tree, offset+1);
6141
    printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr)));
mimaki's avatar
mimaki committed
6142 6143 6144
    break;

  case NODE_COLON3:
6145
    printf("NODE_COLON3: ::%s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6146 6147 6148 6149 6150 6151 6152 6153 6154 6155
    break;

  case NODE_ARRAY:
    printf("NODE_ARRAY:\n");
    dump_recur(mrb, tree, offset+1);
    break;

  case NODE_HASH:
    printf("NODE_HASH:\n");
    while (tree) {
6156
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6157
      printf("key:\n");
cremno's avatar
cremno committed
6158
      mrb_parser_dump(mrb, tree->car->car, offset+2);
6159
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6160
      printf("value:\n");
cremno's avatar
cremno committed
6161
      mrb_parser_dump(mrb, tree->car->cdr, offset+2);
mimaki's avatar
mimaki committed
6162 6163 6164 6165 6166 6167
      tree = tree->cdr;
    }
    break;

  case NODE_SPLAT:
    printf("NODE_SPLAT:\n");
cremno's avatar
cremno committed
6168
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6169 6170 6171 6172
    break;

  case NODE_ASGN:
    printf("NODE_ASGN:\n");
6173
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6174
    printf("lhs:\n");
cremno's avatar
cremno committed
6175
    mrb_parser_dump(mrb, tree->car, offset+2);
6176
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6177
    printf("rhs:\n");
cremno's avatar
cremno committed
6178
    mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6179 6180 6181 6182
    break;

  case NODE_MASGN:
    printf("NODE_MASGN:\n");
6183
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6184 6185 6186 6187 6188
    printf("mlhs:\n");
    {
      node *n2 = tree->car;

      if (n2->car) {
6189
        dump_prefix(tree, offset+2);
h2so5's avatar
h2so5 committed
6190 6191
        printf("pre:\n");
        dump_recur(mrb, n2->car, offset+3);
mimaki's avatar
mimaki committed
6192 6193 6194
      }
      n2 = n2->cdr;
      if (n2) {
h2so5's avatar
h2so5 committed
6195
        if (n2->car) {
6196
          dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6197 6198
          printf("rest:\n");
          if (n2->car == (node*)-1) {
6199
            dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6200 6201 6202
            printf("(empty)\n");
          }
          else {
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6203
            mrb_parser_dump(mrb, n2->car, offset+3);
h2so5's avatar
h2so5 committed
6204 6205 6206 6207 6208
          }
        }
        n2 = n2->cdr;
        if (n2) {
          if (n2->car) {
6209
            dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6210 6211 6212 6213
            printf("post:\n");
            dump_recur(mrb, n2->car, offset+3);
          }
        }
mimaki's avatar
mimaki committed
6214 6215
      }
    }
6216
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6217
    printf("rhs:\n");
cremno's avatar
cremno committed
6218
    mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6219 6220 6221 6222
    break;

  case NODE_OP_ASGN:
    printf("NODE_OP_ASGN:\n");
6223
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6224
    printf("lhs:\n");
cremno's avatar
cremno committed
6225
    mrb_parser_dump(mrb, tree->car, offset+2);
mimaki's avatar
mimaki committed
6226
    tree = tree->cdr;
6227
    dump_prefix(tree, offset+1);
6228
    printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
mimaki's avatar
mimaki committed
6229
    tree = tree->cdr;
cremno's avatar
cremno committed
6230
    mrb_parser_dump(mrb, tree->car, offset+1);
mimaki's avatar
mimaki committed
6231 6232 6233 6234 6235
    break;

  case NODE_SUPER:
    printf("NODE_SUPER:\n");
    if (tree) {
6236
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6237 6238 6239
      printf("args:\n");
      dump_recur(mrb, tree->car, offset+2);
      if (tree->cdr) {
6240
        dump_prefix(tree, offset+1);
h2so5's avatar
h2so5 committed
6241
        printf("block:\n");
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6242
        mrb_parser_dump(mrb, tree->cdr, offset+2);
mimaki's avatar
mimaki committed
6243 6244 6245 6246 6247 6248 6249 6250 6251 6252
      }
    }
    break;

  case NODE_ZSUPER:
    printf("NODE_ZSUPER\n");
    break;

  case NODE_RETURN:
    printf("NODE_RETURN:\n");
cremno's avatar
cremno committed
6253
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6254 6255 6256 6257 6258 6259 6260 6261 6262
    break;

  case NODE_YIELD:
    printf("NODE_YIELD:\n");
    dump_recur(mrb, tree, offset+1);
    break;

  case NODE_BREAK:
    printf("NODE_BREAK:\n");
cremno's avatar
cremno committed
6263
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6264 6265 6266 6267
    break;

  case NODE_NEXT:
    printf("NODE_NEXT:\n");
cremno's avatar
cremno committed
6268
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279
    break;

  case NODE_REDO:
    printf("NODE_REDO\n");
    break;

  case NODE_RETRY:
    printf("NODE_RETRY\n");
    break;

  case NODE_LVAR:
6280
    printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6281 6282 6283
    break;

  case NODE_GVAR:
6284
    printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6285 6286 6287
    break;

  case NODE_IVAR:
6288
    printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6289 6290 6291
    break;

  case NODE_CVAR:
6292
    printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6293 6294 6295
    break;

  case NODE_CONST:
6296
    printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6297 6298
    break;

mattn's avatar
mattn committed
6299 6300
  case NODE_MATCH:
    printf("NODE_MATCH:\n");
6301
    dump_prefix(tree, offset + 1);
mattn's avatar
mattn committed
6302
    printf("lhs:\n");
cremno's avatar
cremno committed
6303
    mrb_parser_dump(mrb, tree->car, offset + 2);
6304
    dump_prefix(tree, offset + 1);
mattn's avatar
mattn committed
6305
    printf("rhs:\n");
cremno's avatar
cremno committed
6306
    mrb_parser_dump(mrb, tree->cdr, offset + 2);
mattn's avatar
mattn committed
6307 6308
    break;

mimaki's avatar
mimaki committed
6309
  case NODE_BACK_REF:
6310
    printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree);
mimaki's avatar
mimaki committed
6311 6312 6313
    break;

  case NODE_NTH_REF:
6314
    printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree);
mimaki's avatar
mimaki committed
6315 6316 6317
    break;

  case NODE_ARG:
6318
    printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree)));
mimaki's avatar
mimaki committed
6319 6320 6321 6322
    break;

  case NODE_BLOCK_ARG:
    printf("NODE_BLOCK_ARG:\n");
cremno's avatar
cremno committed
6323
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6324 6325 6326
    break;

  case NODE_INT:
6327
    printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car);
mimaki's avatar
mimaki committed
6328 6329 6330 6331 6332 6333 6334 6335
    break;

  case NODE_FLOAT:
    printf("NODE_FLOAT %s\n", (char*)tree);
    break;

  case NODE_NEGATE:
    printf("NODE_NEGATE\n");
cremno's avatar
cremno committed
6336
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6337 6338 6339
    break;

  case NODE_STR:
6340
    printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
mimaki's avatar
mimaki committed
6341 6342 6343 6344 6345 6346 6347
    break;

  case NODE_DSTR:
    printf("NODE_DSTR\n");
    dump_recur(mrb, tree, offset+1);
    break;

mattn's avatar
mattn committed
6348 6349 6350 6351 6352 6353 6354 6355 6356
  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;

mattn's avatar
mattn committed
6357
  case NODE_REGX:
6358
    printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr);
mattn's avatar
mattn committed
6359 6360
    break;

6361 6362 6363
  case NODE_DREGX:
    printf("NODE_DREGX\n");
    dump_recur(mrb, tree->car, offset+1);
6364
    dump_prefix(tree, offset);
6365
    printf("tail: %s\n", (char*)tree->cdr->cdr->car);
6366 6367 6368 6369 6370 6371 6372 6373
    if (tree->cdr->cdr->cdr->car) {
      dump_prefix(tree, offset);
      printf("opt: %s\n", (char*)tree->cdr->cdr->cdr->car);
    }
    if (tree->cdr->cdr->cdr->cdr) {
      dump_prefix(tree, offset);
      printf("enc: %s\n", (char*)tree->cdr->cdr->cdr->cdr);
    }
6374 6375
    break;

mimaki's avatar
mimaki committed
6376
  case NODE_SYM:
6377 6378
    printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)),
           (int)(intptr_t)tree);
mimaki's avatar
mimaki committed
6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398
    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",
h2so5's avatar
h2so5 committed
6399 6400
        mrb_sym2name(mrb, sym(tree->car)),
        mrb_sym2name(mrb, sym(tree->cdr)));
mimaki's avatar
mimaki committed
6401 6402 6403
    break;

  case NODE_UNDEF:
6404 6405 6406 6407
    printf("NODE_UNDEF");
    {
      node *t = tree;
      while (t) {
h2so5's avatar
h2so5 committed
6408 6409
        printf(" %s", mrb_sym2name(mrb, sym(t->car)));
        t = t->cdr;
6410 6411 6412
      }
    }
    printf(":\n");
mimaki's avatar
mimaki committed
6413 6414 6415 6416 6417
    break;

  case NODE_CLASS:
    printf("NODE_CLASS:\n");
    if (tree->car->car == (node*)0) {
6418
      dump_prefix(tree, offset+1);
6419
      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6420 6421
    }
    else if (tree->car->car == (node*)1) {
6422
      dump_prefix(tree, offset+1);
6423
      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6424 6425
    }
    else {
cremno's avatar
cremno committed
6426
      mrb_parser_dump(mrb, tree->car->car, offset+1);
6427
      dump_prefix(tree, offset+1);
6428
      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6429 6430
    }
    if (tree->cdr->car) {
6431
      dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6432
      printf("super:\n");
cremno's avatar
cremno committed
6433
      mrb_parser_dump(mrb, tree->cdr->car, offset+2);
mimaki's avatar
mimaki committed
6434
    }
6435
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6436
    printf("body:\n");
cremno's avatar
cremno committed
6437
    mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2);
mimaki's avatar
mimaki committed
6438 6439 6440 6441 6442
    break;

  case NODE_MODULE:
    printf("NODE_MODULE:\n");
    if (tree->car->car == (node*)0) {
6443
      dump_prefix(tree, offset+1);
6444
      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6445 6446
    }
    else if (tree->car->car == (node*)1) {
6447
      dump_prefix(tree, offset+1);
6448
      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6449 6450
    }
    else {
cremno's avatar
cremno committed
6451
      mrb_parser_dump(mrb, tree->car->car, offset+1);
6452
      dump_prefix(tree, offset+1);
6453
      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
mimaki's avatar
mimaki committed
6454
    }
6455
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6456
    printf("body:\n");
cremno's avatar
cremno committed
6457
    mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
mimaki's avatar
mimaki committed
6458 6459 6460 6461
    break;

  case NODE_SCLASS:
    printf("NODE_SCLASS:\n");
cremno's avatar
cremno committed
6462
    mrb_parser_dump(mrb, tree->car, offset+1);
6463
    dump_prefix(tree, offset+1);
mimaki's avatar
mimaki committed
6464
    printf("body:\n");
cremno's avatar
cremno committed
6465
    mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
mimaki's avatar
mimaki committed
6466 6467 6468 6469
    break;

  case NODE_DEF:
    printf("NODE_DEF:\n");
6470
    dump_prefix(tree, offset+1);
6471
    printf("%s\n", mrb_sym2name(mrb, sym(tree->car)));
mimaki's avatar
mimaki committed
6472 6473 6474
    tree = tree->cdr;
    {
      node *n2 = tree->car;
6475
      mrb_bool first_lval = TRUE;
mimaki's avatar
mimaki committed
6476

6477
      if (n2 && (n2->car || n2->cdr)) {
6478
        dump_prefix(n2, offset+1);
h2so5's avatar
h2so5 committed
6479
        printf("local variables:\n");
6480
        dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6481 6482
        while (n2) {
          if (n2->car) {
6483
            if (!first_lval) printf(", ");
h2so5's avatar
h2so5 committed
6484
            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
6485
            first_lval = FALSE;
h2so5's avatar
h2so5 committed
6486 6487 6488 6489
          }
          n2 = n2->cdr;
        }
        printf("\n");
mimaki's avatar
mimaki committed
6490 6491 6492 6493 6494 6495 6496
      }
    }
    tree = tree->cdr;
    if (tree->car) {
      node *n = tree->car;

      if (n->car) {
6497
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6498 6499
        printf("mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
mimaki's avatar
mimaki committed
6500 6501 6502
      }
      n = n->cdr;
      if (n->car) {
6503
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6504 6505 6506 6507 6508
        printf("optional args:\n");
        {
          node *n2 = n->car;

          while (n2) {
6509
            dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6510
            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6511
            mrb_parser_dump(mrb, n2->car->cdr, 0);
h2so5's avatar
h2so5 committed
6512 6513 6514
            n2 = n2->cdr;
          }
        }
mimaki's avatar
mimaki committed
6515 6516 6517
      }
      n = n->cdr;
      if (n->car) {
6518
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6519
        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
mimaki's avatar
mimaki committed
6520 6521 6522
      }
      n = n->cdr;
      if (n->car) {
6523
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6524 6525
        printf("post mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
mimaki's avatar
mimaki committed
6526
      }
6527
      if (n->cdr) {
6528
        dump_prefix(n, offset+1);
6529
        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
mimaki's avatar
mimaki committed
6530 6531
      }
    }
cremno's avatar
cremno committed
6532
    mrb_parser_dump(mrb, tree->cdr->car, offset+1);
mimaki's avatar
mimaki committed
6533 6534 6535 6536
    break;

  case NODE_SDEF:
    printf("NODE_SDEF:\n");
cremno's avatar
cremno committed
6537
    mrb_parser_dump(mrb, tree->car, offset+1);
mimaki's avatar
mimaki committed
6538
    tree = tree->cdr;
6539
    dump_prefix(tree, offset+1);
6540
    printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
mimaki's avatar
mimaki committed
6541 6542 6543 6544 6545
    tree = tree->cdr->cdr;
    if (tree->car) {
      node *n = tree->car;

      if (n->car) {
6546
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6547 6548
        printf("mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
mimaki's avatar
mimaki committed
6549 6550 6551
      }
      n = n->cdr;
      if (n->car) {
6552
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6553 6554 6555 6556 6557
        printf("optional args:\n");
        {
          node *n2 = n->car;

          while (n2) {
6558
            dump_prefix(n2, offset+2);
h2so5's avatar
h2so5 committed
6559
            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
6560
            mrb_parser_dump(mrb, n2->car->cdr, 0);
h2so5's avatar
h2so5 committed
6561 6562 6563
            n2 = n2->cdr;
          }
        }
mimaki's avatar
mimaki committed
6564 6565 6566
      }
      n = n->cdr;
      if (n->car) {
6567
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6568
        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
mimaki's avatar
mimaki committed
6569 6570 6571
      }
      n = n->cdr;
      if (n->car) {
6572
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6573 6574
        printf("post mandatory args:\n");
        dump_recur(mrb, n->car, offset+2);
mimaki's avatar
mimaki committed
6575 6576 6577
      }
      n = n->cdr;
      if (n) {
6578
        dump_prefix(n, offset+1);
h2so5's avatar
h2so5 committed
6579
        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
mimaki's avatar
mimaki committed
6580 6581 6582
      }
    }
    tree = tree->cdr;
cremno's avatar
cremno committed
6583
    mrb_parser_dump(mrb, tree->car, offset+1);
mimaki's avatar
mimaki committed
6584 6585 6586 6587
    break;

  case NODE_POSTEXE:
    printf("NODE_POSTEXE:\n");
cremno's avatar
cremno committed
6588
    mrb_parser_dump(mrb, tree, offset+1);
mimaki's avatar
mimaki committed
6589 6590
    break;

FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
6591
  case NODE_HEREDOC:
6592
    printf("NODE_HEREDOC (<<%s):\n", ((parser_heredoc_info*)tree)->term);
6593
    dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
FUKUZAWA-Tadashi's avatar
FUKUZAWA-Tadashi committed
6594 6595
    break;

mimaki's avatar
mimaki committed
6596
  default:
6597
    printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
mimaki's avatar
mimaki committed
6598 6599
    break;
  }
6600
#endif
mimaki's avatar
mimaki committed
6601
}